baseline: OpenMU upstream b5a0961 (fresh source)
This commit is contained in:
13
.gemini/config.yaml
Normal file
13
.gemini/config.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
have_fun: false
|
||||||
|
memory_config:
|
||||||
|
disabled: false
|
||||||
|
code_review:
|
||||||
|
disable: false
|
||||||
|
comment_severity_threshold: MEDIUM
|
||||||
|
max_review_comments: -1
|
||||||
|
pull_request_opened:
|
||||||
|
help: false
|
||||||
|
summary: true
|
||||||
|
code_review: true
|
||||||
|
include_drafts: false
|
||||||
|
ignore_patterns: []
|
||||||
10
.gitattributes
vendored
Normal file
10
.gitattributes
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# Explicitly declare text files you want to always be normalized and converted
|
||||||
|
# to native line endings on checkout.
|
||||||
|
*.cpp text
|
||||||
|
*.h text
|
||||||
|
*.cs text
|
||||||
|
*.csproj text
|
||||||
|
*.sln text
|
||||||
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- OS: [e.g. iOS8.1]
|
||||||
|
- Browser [e.g. stock browser, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
10
.github/ISSUE_TEMPLATE/other-request.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/other-request.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: Other request
|
||||||
|
about: Ask questions or similar
|
||||||
|
title: ''
|
||||||
|
labels: question
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
41
.github/workflows/claude.yml
vendored
Normal file
41
.github/workflows/claude.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: Claude Code
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
pull_request_review_comment:
|
||||||
|
types: [created]
|
||||||
|
issues:
|
||||||
|
types: [opened, assigned]
|
||||||
|
pull_request_review:
|
||||||
|
types: [submitted]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
claude:
|
||||||
|
if: |
|
||||||
|
github.actor == 'sven-n' && (
|
||||||
|
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||||
|
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||||
|
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||||
|
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||||
|
)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
id-token: write
|
||||||
|
actions: read
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Run Claude Code
|
||||||
|
id: claude
|
||||||
|
uses: anthropics/claude-code-action@v1
|
||||||
|
with:
|
||||||
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
|
additional_permissions: |
|
||||||
|
actions: read
|
||||||
17
.github/workflows/dotnetcore.yml
vendored
Normal file
17
.github/workflows/dotnetcore.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
name: .NET Core
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Setup .NET Core
|
||||||
|
uses: actions/setup-dotnet@v1
|
||||||
|
with:
|
||||||
|
dotnet-version: 10.0.x
|
||||||
|
- name: Build with dotnet
|
||||||
|
run: dotnet publish src/Startup/MUnique.OpenMU.Startup.csproj --configuration Release -p:ci=true
|
||||||
40
.github/workflows/publish.yml
vendored
Normal file
40
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: publish to nuget
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
name: Publish packages to nuget
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Setup .NET Core
|
||||||
|
uses: actions/setup-dotnet@v1
|
||||||
|
with:
|
||||||
|
dotnet-version: 10.0.x
|
||||||
|
|
||||||
|
- name: publish MUnique.OpenMU.PlugIns on version change
|
||||||
|
uses: rohith/publish-nuget@5fdc86fb81a38b37521c9f153bfb60ac44e7ba93
|
||||||
|
with:
|
||||||
|
PROJECT_FILE_PATH: src/PlugIns/MUnique.OpenMU.PlugIns.csproj
|
||||||
|
TAG_COMMIT: false
|
||||||
|
NUGET_KEY: ${{secrets.NUGET_KEY}}
|
||||||
|
PACKAGE_NAME: munique.openmu.plugins
|
||||||
|
|
||||||
|
- name: publish MUnique.OpenMU.Network on version change
|
||||||
|
uses: rohith/publish-nuget@5fdc86fb81a38b37521c9f153bfb60ac44e7ba93
|
||||||
|
with:
|
||||||
|
PROJECT_FILE_PATH: src/Network/MUnique.OpenMU.Network.csproj
|
||||||
|
TAG_COMMIT: false
|
||||||
|
NUGET_KEY: ${{secrets.NUGET_KEY}}
|
||||||
|
PACKAGE_NAME: munique.openmu.network
|
||||||
|
|
||||||
|
- name: publish MUnique.OpenMU.Network.Packets on version change
|
||||||
|
uses: rohith/publish-nuget@5fdc86fb81a38b37521c9f153bfb60ac44e7ba93
|
||||||
|
with:
|
||||||
|
PROJECT_FILE_PATH: src/Network/Packets/MUnique.OpenMU.Network.Packets.csproj
|
||||||
|
TAG_COMMIT: true
|
||||||
|
TAG_FORMAT: v*
|
||||||
|
NUGET_KEY: ${{secrets.NUGET_KEY}}
|
||||||
|
PACKAGE_NAME: munique.openmu.network.packets
|
||||||
325
.gitignore
vendored
Normal file
325
.gitignore
vendored
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
**/content/bundles/*.*
|
||||||
|
|
||||||
|
# Visual Studio 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
**/Properties/launchSettings.json
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# VS Code
|
||||||
|
.vscode/
|
||||||
|
*.lscache
|
||||||
|
|
||||||
|
# CodeRush
|
||||||
|
.cr/
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# SubVersion
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# Pandoc html result files
|
||||||
|
doc/*.htm
|
||||||
|
|
||||||
|
# text files; for documentation etc. use markdown
|
||||||
|
*.txt
|
||||||
|
|
||||||
|
# bundles
|
||||||
|
src/AdminPanel/wwwroot/content/css/app.css
|
||||||
|
src/AdminPanel/wwwroot/content/css/app.min.css
|
||||||
|
src/AdminPanel/wwwroot/content/js/app.js
|
||||||
|
src/AdminPanel/wwwroot/content/js/app.js.map
|
||||||
|
|
||||||
|
# Data
|
||||||
|
.data/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# Mac OS filesystem files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# AI
|
||||||
|
.opencode/
|
||||||
36
CONTRIBUTING.md
Normal file
36
CONTRIBUTING.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# Contributions
|
||||||
|
|
||||||
|
Contributions are welcome if they meet the following criteria:
|
||||||
|
|
||||||
|
* Language is english.
|
||||||
|
|
||||||
|
* Code should be StyleCop compliant - this project uses the [StyleCop.Analyzers](https://www.nuget.org/packages/StyleCop.Analyzers/)
|
||||||
|
for VS2019 so you should see issues directly as warnings.
|
||||||
|
|
||||||
|
* Coding style (naming, etc.) and quality should fit to the current state.
|
||||||
|
|
||||||
|
* No code copied/converted from the well-known decompiled source of the
|
||||||
|
original server.
|
||||||
|
|
||||||
|
If you want to contribute, please create a new issue for the feature or bug (if
|
||||||
|
the issue doesn't exist yet) so we can see who is working on something and can
|
||||||
|
discuss possible solutions. If it's a small thing, you can also just send a
|
||||||
|
pull request without adding an issue.
|
||||||
|
|
||||||
|
Apart of that, contributions from non-developers are welcome as well. You can
|
||||||
|
test the server, submit issues or suggestions, packet descriptions or
|
||||||
|
documentations about the concepts and mechanics of the game itself. Please use
|
||||||
|
markdown files/syntax for this purpose.
|
||||||
|
|
||||||
|
If you have questions about that, don't hesitate to ask in our [discord channel](https://discord.gg/2u5Agkd)
|
||||||
|
or by submitting an issue.
|
||||||
|
|
||||||
|
## How to contribute code
|
||||||
|
|
||||||
|
If you want to contribute code, please do the following steps:
|
||||||
|
|
||||||
|
1. fork this project from the original MUnique OpenMU Project.
|
||||||
|
2. create a feature branch from the master branch
|
||||||
|
3. commit your changes to your feature branch
|
||||||
|
4. submit a pull request to the original master branch
|
||||||
|
5. lean back, wait for the code review and merge :)
|
||||||
7
LICENSE
Normal file
7
LICENSE
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Copyright 2017 MUnique
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
145
QuickStart.md
Normal file
145
QuickStart.md
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# Quick Start OpenMU
|
||||||
|
|
||||||
|
General requirements:
|
||||||
|
|
||||||
|
* Free TCP ports:
|
||||||
|
* 80 (admin panel)
|
||||||
|
* 55901 - 55906 (game servers)
|
||||||
|
* 44405 - 44406 (connect servers)
|
||||||
|
* 44405: default connection port for the original client
|
||||||
|
* 44406: connection port especially for the [open source client](https://github.com/sven-n/MuMain)
|
||||||
|
* 55980 (chat server)
|
||||||
|
|
||||||
|
* A game client (check [our Discord](https://discord.gg/2u5Agkd) FAQs)
|
||||||
|
* Knowledge or way to start the game client, so that it connects to the server. Our Launcher will do that.
|
||||||
|
|
||||||
|
* Launcher binaries: [MUnique.OpenMU.ClientLauncher v0.9.6.zip](https://github.com/MUnique/OpenMU/releases/download/v0.9.0/MUnique.OpenMU.ClientLauncher_0.9.6.zip)
|
||||||
|
* It requires the [.NET 10 runtime](https://dotnet.microsoft.com/download/dotnet/10.0) or higher
|
||||||
|
* If your server and client runs on your local host, use any IP of 127.x.x.x, except 127.0.0.1, because this one is blocked by the client. For example, you could use 127.127.127.127
|
||||||
|
|
||||||
|
This guide describes two ways of starting the server. Use Docker, if you just
|
||||||
|
want to play around. If you want to develop or debug the server, choose the
|
||||||
|
manual way.
|
||||||
|
|
||||||
|
As you can see on the connect server ports, the server is initialized for two different clients by default.
|
||||||
|
They can connect to the same game servers through different ports. However, if you connect to the wrong port,
|
||||||
|
it may currently still work all correctly, you'll just get warnings in the logs. However, as soon as
|
||||||
|
we change encryption keys or methods, this will change.
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
Please take a look at the deploy-folder of this project. There you'll find a more
|
||||||
|
detailed guide about how to set up this project.
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
It's possible to define additional environment variables to influence the
|
||||||
|
postgres database connection strings.
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
|------|---------------------|
|
||||||
|
| DB_HOST | The hostname of the database. If the local configuration file is still configured to use 'localhost', the value of this variable replaces it |
|
||||||
|
| DB_ADMIN_USER | The user name of the postgres admin account. If the local configuration file is still configured to use 'postgres' for the user name of the admin (first entry in the ConnectionSettings.xml), the value of this variable replaces it. |
|
||||||
|
| DB_ADMIN_PW | The password of the postgres admin account. If the local configuration file is still configured to use 'admin' for the user password of the admin (first entry in the ConnectionSettings.xml), the value of this variable replaces it. |
|
||||||
|
|
||||||
|
## Manually
|
||||||
|
|
||||||
|
Use this way, if you want to develop or debug for OpenMU.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
* Windows OS, 10 or higher
|
||||||
|
|
||||||
|
* It runs under Linux and MacOS, too. However, this guide describes it for
|
||||||
|
windows.
|
||||||
|
|
||||||
|
* PostgreSQL installed
|
||||||
|
|
||||||
|
* Visual Studio 2026 installed, with workloads for ASP.NET Web development
|
||||||
|
and .NET Desktop development. Please keep it up-to-date to prevent any issues.
|
||||||
|
|
||||||
|
* Visual Studio Extension "Web Compiler 2022+", if you plan to edit SCSS files
|
||||||
|
for the admin panel.
|
||||||
|
* https://marketplace.visualstudio.com/items?itemName=Failwyn.WebCompiler64
|
||||||
|
|
||||||
|
* [.NET SDK 10](https://dotnet.microsoft.com/download/dotnet/10.0)
|
||||||
|
(it should be included in Visual Studio 2026)
|
||||||
|
* `winget install Microsoft.DotNet.SDK.10`
|
||||||
|
|
||||||
|
* [NodeJS 16+](https://nodejs.org) installed
|
||||||
|
* `winget install OpenJS.NodeJS.LTS`
|
||||||
|
|
||||||
|
* This repository cloned
|
||||||
|
|
||||||
|
If you have that, you'll need to do:
|
||||||
|
|
||||||
|
* Open the solution of OpenMU with Visual Studio
|
||||||
|
|
||||||
|
* Right click the solution and 'Restore NuGet Packages'
|
||||||
|
|
||||||
|
* Edit src\Persistence\EntityFramework\ConnectionSettings.xml, so that the
|
||||||
|
connection strings are correct - however only the user/password of the first
|
||||||
|
and second connection string need to be correct. The server will try to create
|
||||||
|
the other roles specified by the settings.
|
||||||
|
|
||||||
|
* Build the solution
|
||||||
|
|
||||||
|
* Start MUnique.OpenMU.Startup
|
||||||
|
|
||||||
|
* If required, it will create the database schemas, the required roles and
|
||||||
|
gives permissions to this roles.
|
||||||
|
|
||||||
|
* Optional: You can reinitialize the database by adding a ```-reinit``` parameter.
|
||||||
|
|
||||||
|
* When the Admin Panel is initialized, go to <http://localhost/>. Then you
|
||||||
|
should see three gameservers, the chat server and two connect servers. Start
|
||||||
|
the connect servers and at least one gameserver.
|
||||||
|
|
||||||
|
* If you update to a newer state of the master-branch, it could be possible
|
||||||
|
that you have to update the database and configuration.
|
||||||
|
You can find updates in the admin panel.
|
||||||
|
|
||||||
|
* Then you can connect to the server through the game client.
|
||||||
|
|
||||||
|
## Helpful (optional) steps
|
||||||
|
|
||||||
|
* __Auto Start__: If you don't want to start each server listener after starting
|
||||||
|
the process, you can either activate "Auto Start"
|
||||||
|
|
||||||
|
* in the admin panel at ```Configuration -> System```,
|
||||||
|
|
||||||
|
* or with the start parameter ```-autostart```.
|
||||||
|
|
||||||
|
* __IP Resolving__: If you encounter disconnects after selecting a server, it's most
|
||||||
|
likely a wrong setting for the IP resolver. You can change it easily over the
|
||||||
|
admin panel at ```Configuration -> System``` as well.
|
||||||
|
You may also change the setting by providing start parameters or environment
|
||||||
|
parameters, however I just recommend this for experienced users. Look at this
|
||||||
|
[Readme](src/Startup/Readme.md) for more information.
|
||||||
|
|
||||||
|
* __Changing the game version__: If you want to player another version than
|
||||||
|
season 6, you may initialize the database with another game version.
|
||||||
|
You can do this over the admin panel as well, at the ```Setup``` page.
|
||||||
|
|
||||||
|
## Test Accounts
|
||||||
|
|
||||||
|
To test some features of the server, test accounts are created automatically
|
||||||
|
when the database is initialized.
|
||||||
|
|
||||||
|
These are the user names:
|
||||||
|
|
||||||
|
* test0 - test9: General test accounts, level 1 to 90, in 10 level steps
|
||||||
|
|
||||||
|
Season 6 only:
|
||||||
|
* test300: General test account with level 300
|
||||||
|
* test400: General test account with level 400, master characters
|
||||||
|
* testgm: Test account of a game master
|
||||||
|
* testgm2: Test account of a game master with summoner and rage fighter characters
|
||||||
|
* testunlock: Test account without characters, but unlocked character classes
|
||||||
|
* quest1: Test account for the level 150 quests
|
||||||
|
* quest2: Test account for the level 220 quests
|
||||||
|
* quest3: Test account for the level 400 quests
|
||||||
|
* ancient: Test account with ancient item sets, level 330 characters
|
||||||
|
* socket: Test account with socket item sets, level 380 characters
|
||||||
|
|
||||||
|
The __passwords__ of these accounts are the __same as the user name__.
|
||||||
131
README.md
Normal file
131
README.md
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# OpenMU Project
|
||||||
|
|
||||||
|
[](LICENSE)
|
||||||
|
[](https://www.codacy.com/gh/MUnique/OpenMU/dashboard?utm_source=github.com&utm_medium=referral&utm_content=MUnique/OpenMU&utm_campaign=Badge_Grade)
|
||||||
|
[](https://deepwiki.com/MUnique/OpenMU)
|
||||||
|
[](https://discord.gg/2u5Agkd)
|
||||||
|
|
||||||
|
| Platform |Build Status |
|
||||||
|
|----------------|----------------------|
|
||||||
|
| Windows |  |
|
||||||
|
| Linux (Docker) | [](https://hub.docker.com/r/munique/openmu) |
|
||||||
|
|
||||||
|
| NuGet Packages | |
|
||||||
|
|----------------|---|
|
||||||
|
| MUnique.OpenMU.Network | [](https://www.nuget.org/packages/MUnique.OpenMU.Network/) |
|
||||||
|
| MUnique.OpenMU.Network.Packets | [](https://www.nuget.org/packages/MUnique.OpenMU.Network.Packets/) |
|
||||||
|
|
||||||
|
This project aims to create an easy to use, extendable and customizable server
|
||||||
|
for a MMORPG called "MU Online".
|
||||||
|
The server supports multiple versions of the game, but the main focus is
|
||||||
|
version of Season 6 Episode 3 using the ENG (english) protocol. Additionally,
|
||||||
|
the long-term focus is on the [open source client](https://github.com/sven-n/MuMain)
|
||||||
|
which supports a slightly extended network protocol.
|
||||||
|
However, parts of the software can also be suitable for the development of
|
||||||
|
other games, even for other kind of games.
|
||||||
|
|
||||||
|
The code is a complete rewrite from scratch - it's not based on pre-existing
|
||||||
|
projects, and it's also explicitly not based on decompiled server sources or
|
||||||
|
their countless derivates.
|
||||||
|
|
||||||
|
There also exists a [blog](https://munique.net) which may contain some valuable
|
||||||
|
information about this development.
|
||||||
|
|
||||||
|
## Current project state
|
||||||
|
|
||||||
|
This project is currently under development without any release.
|
||||||
|
You can try the current state by using the available docker image, also
|
||||||
|
mentioned in the [quick start guide](QuickStart.md).
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
|
This project is released under the MIT license (see LICENSE file).
|
||||||
|
|
||||||
|
## Used technologies
|
||||||
|
|
||||||
|
The project is mainly written in C# and targets .NET 10.0.
|
||||||
|
|
||||||
|
The servers admin panel is hosted on an embedded ASP.NET Core webserver (Kestrel)
|
||||||
|
and implemented as Blazor Server App.
|
||||||
|
|
||||||
|
At the moment the persistence layer uses the [Entity Framework Core](https://github.com/aspnet/EntityFrameworkCore)
|
||||||
|
and [PostgreSQL](https://www.postgresql.org) as database. Additionally, it's
|
||||||
|
also possible to start it in a non-persistent in-memory mode.
|
||||||
|
|
||||||
|
The project is prepared to be hosted in a single process or distributed in multiple processes.
|
||||||
|
For the communication between the processes, we use [Dapr](https://dapr.io/).
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
We provide Docker images and docker-compose files for easy deployment.
|
||||||
|
Please take a look at the deploy-folder of this project.
|
||||||
|
|
||||||
|
## Contributions
|
||||||
|
|
||||||
|
Contributions are welcome if they meet the following criteria:
|
||||||
|
|
||||||
|
* Language is english.
|
||||||
|
|
||||||
|
* Code should be StyleCop compliant - this project uses the [StyleCop.Analyzers](https://www.nuget.org/packages/StyleCop.Analyzers/)
|
||||||
|
for VS2022 so you should see issues directly as warnings.
|
||||||
|
|
||||||
|
* Coding style (naming, etc.) and quality should fit to the current state.
|
||||||
|
|
||||||
|
* No code copied/converted from the well-known decompiled source of the
|
||||||
|
original server.
|
||||||
|
|
||||||
|
If you want to contribute, please create a new issue for the feature or bug (if
|
||||||
|
the issue doesn't exist yet) so we can see who is working on something and can
|
||||||
|
discuss possible solutions. If it's a small thing, you can also just send a
|
||||||
|
pull request without adding an issue.
|
||||||
|
|
||||||
|
Apart of that, contributions from non-developers are welcome as well. You can
|
||||||
|
test the server, submit issues or suggestions, packet descriptions or
|
||||||
|
documentations about the concepts and mechanics of the game itself. Please use
|
||||||
|
markdown files/syntax for this purpose.
|
||||||
|
|
||||||
|
If you have questions about that, don't hesitate to ask in our [discord channel](https://discord.gg/2u5Agkd)
|
||||||
|
or by submitting an issue.
|
||||||
|
|
||||||
|
## How to contribute code
|
||||||
|
|
||||||
|
If you want to contribute code, please do the following steps:
|
||||||
|
|
||||||
|
1. fork this project from the original MUnique OpenMU Project.
|
||||||
|
2. create a feature branch from the master branch
|
||||||
|
3. commit your changes to your feature branch
|
||||||
|
4. please test your changes, don't send AI generated code without testing it yourself
|
||||||
|
5. submit a pull request to the original master branch
|
||||||
|
6. wait for the code review and merge :)
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
Please have a look at the [quick start guide](QuickStart.md).
|
||||||
|
|
||||||
|
## Gameplay differences to the original server
|
||||||
|
|
||||||
|
This project doesn't have the goal to copy the original MU Online server
|
||||||
|
behavior to 100 %. This is not entirely possible, because the original server
|
||||||
|
is written in another programming language and has a completely different
|
||||||
|
architecture.
|
||||||
|
With some points we make our life easier in this project, with other points we
|
||||||
|
try to improve the gameplay.
|
||||||
|
|
||||||
|
### Calculations
|
||||||
|
|
||||||
|
The calculations of attribute values (like character damage decrement etc.) are
|
||||||
|
done with 32 bit float numbers and without rounding off, like the original
|
||||||
|
server does at some places.
|
||||||
|
E.g. distributed stat points always have effect, while in the original server
|
||||||
|
effects might get rounded down. For example, when 4 points of strength gives 1
|
||||||
|
base damage, the original server doesn't calculate a fraction of 1 damage for
|
||||||
|
3 points, while OpenMU calculates 0.75 damage. This damage
|
||||||
|
has then an effect in further calculations.
|
||||||
|
|
||||||
|
### Countdown when changing character or sub-server
|
||||||
|
|
||||||
|
The original server uses a five second countdown when a player wants to change
|
||||||
|
his character or the sub-server. Maybe this was done for some performance
|
||||||
|
reasons, as the original server would then save the character/account data.
|
||||||
|
We think that's really annoying and see no real value in that, so we don't use
|
||||||
|
a countdown.
|
||||||
36
azure-pipelines.yml
Normal file
36
azure-pipelines.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# ASP.NET Core
|
||||||
|
# Build and test ASP.NET Core projects targeting .NET Core.
|
||||||
|
# Add steps that run tests, create a NuGet package, deploy, and more:
|
||||||
|
# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
- master
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: 'windows-2022'
|
||||||
|
|
||||||
|
variables:
|
||||||
|
buildConfiguration: 'Release'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- task: UseDotNet@2
|
||||||
|
displayName: 'Install .NET Core SDK'
|
||||||
|
inputs:
|
||||||
|
version: 10.0.x
|
||||||
|
performMultiLevelLookup: true
|
||||||
|
includePreviewVersions: true # Required for preview versions
|
||||||
|
|
||||||
|
- script: dotnet restore
|
||||||
|
workingDirectory: src
|
||||||
|
displayName: 'dotnet restore'
|
||||||
|
|
||||||
|
- script: dotnet build --configuration $(buildConfiguration) -p:ci=true
|
||||||
|
workingDirectory: src
|
||||||
|
displayName: 'dotnet build $(buildConfiguration)'
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: 'dotnet test'
|
||||||
|
inputs:
|
||||||
|
command: test
|
||||||
|
projects: 'tests/*Tests/*.csproj'
|
||||||
|
arguments: '--configuration $(buildConfiguration) --no-build'
|
||||||
90
deploy/README.md
Normal file
90
deploy/README.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# Deployment
|
||||||
|
|
||||||
|
The recommended way to deploy OpenMU is through Docker. Depending on the scale
|
||||||
|
you need, we have multiple ways to do that.
|
||||||
|
|
||||||
|
## All-in-one
|
||||||
|
|
||||||
|
The [all-in-one deployment](/all-in-one/) is recommended, if you want to host on
|
||||||
|
a small machine with a low amount of players.
|
||||||
|
In this case, all kinds of OpenMU subsystems (ConnectServer, GameServer, LoginServer,
|
||||||
|
AdminPanel, ...) are running in one process.
|
||||||
|
|
||||||
|
### Pros
|
||||||
|
|
||||||
|
* No communication overhead between subsystems, therefore slightly faster
|
||||||
|
* Simpler deployment
|
||||||
|
* Smaller memory footprint. Since we run all in one process, we don't have the
|
||||||
|
overhead of multiple processes, runtimes and can share data.
|
||||||
|
* Easier to observe and debug, no additional tools required
|
||||||
|
|
||||||
|
### Cons
|
||||||
|
|
||||||
|
* Harder to scale - only by scaling up your single machine
|
||||||
|
* Lower resiliency. If one subsystem crashes the process, the whole thing goes
|
||||||
|
down
|
||||||
|
* It's a more or less self-contained system which is harder to extend
|
||||||
|
|
||||||
|
## All-in-one with Traefik as Reverse Proxy
|
||||||
|
|
||||||
|
The [all-in-one with traefik deployment](/deploy/all-in-one-traefik/) is recommended,
|
||||||
|
if you want to host on a small machine with a low amount of players and want to host
|
||||||
|
your MuOnline Website on the same machine.
|
||||||
|
|
||||||
|
Once Traefik works as a Reverse Proxy, you can handle miltiple website without
|
||||||
|
change the default port to HTTP/HTTPS connections.
|
||||||
|
|
||||||
|
Addin a few labels to your container, you will tell Traefik how to handle incoming
|
||||||
|
requests and he will redirect to the correct website.
|
||||||
|
|
||||||
|
### Pros
|
||||||
|
|
||||||
|
* No communication overhead between subsystems, therefore slightly faster
|
||||||
|
* Simpler deployment
|
||||||
|
* Smaller memory footprint. Since we run all in one process, we don't have the
|
||||||
|
overhead of multiple processes, runtimes and can share data.
|
||||||
|
* Easier to observe and debug, no additional tools required
|
||||||
|
* You can have multi websites with auto renew SSL Certificates
|
||||||
|
* Expose only 80 and 443 ports for websites and admin panel.
|
||||||
|
Traefik knows what to do
|
||||||
|
|
||||||
|
### Cons
|
||||||
|
|
||||||
|
* Harder to scale - only by scaling up your single machine
|
||||||
|
* Lower resiliency. If one subsystem crashes the process, the whole thing goes
|
||||||
|
down
|
||||||
|
* It's a more or less self-contained system which is harder to extend
|
||||||
|
|
||||||
|
## Distributed
|
||||||
|
|
||||||
|
*!!! CURRENTLY BROKEN AND UNSUPPORTED, DOCS ARE OUT OF DATE !!!*
|
||||||
|
|
||||||
|
It's also possible to host OpenMU in a [distributed](/distributed/) way.
|
||||||
|
However, this introduces a lot more complexity and you should know what you're doing.
|
||||||
|
The communication between the subsystems is handled with Dapr.
|
||||||
|
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
* It's currently unsupported due to several issues we have to resolve first.
|
||||||
|
Feel free to contribute for the following issues: <https://github.com/MUnique/OpenMU/issues?q=is%3Aissue%20state%3Aopen%20label%3Adistributed-deployment>
|
||||||
|
* This way of hosting OpenMU is more complex and requires a good understanding
|
||||||
|
of distributed systems.
|
||||||
|
* This deployment requires more resources (CPU, RAM, Disk, Network).
|
||||||
|
|
||||||
|
### Pros
|
||||||
|
|
||||||
|
* Easier to scale. For example, if you need additional game servers you simply
|
||||||
|
add more containers.
|
||||||
|
* Higher resiliency. If one subsystem crashes, the others are not affected.
|
||||||
|
* It's easier to add more subsystems, even custom ones.
|
||||||
|
For example, one could subscribe on already published events like guild messages
|
||||||
|
or letters.
|
||||||
|
Such a subsystem could forward messages to other systems (E-Mail, Discord, etc.).
|
||||||
|
|
||||||
|
### Cons
|
||||||
|
|
||||||
|
* Communication overhead between subsystems.
|
||||||
|
* Higher memory footprint, since we run multiple docker containers
|
||||||
|
(each with their own .net runtime) which can't share some data.
|
||||||
|
* Harder to observe and debug. We added some stuff to compensate that (Loki,
|
||||||
|
Grafana, Prometheus, Zipkin), but they require additional resources, too.
|
||||||
25
deploy/all-in-one-traefik/.dockerignore
Normal file
25
deploy/all-in-one-traefik/.dockerignore
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
1
deploy/all-in-one-traefik/.env.example
Normal file
1
deploy/all-in-one-traefik/.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DOMAIN=domain.com
|
||||||
2
deploy/all-in-one-traefik/.gitignore
vendored
Normal file
2
deploy/all-in-one-traefik/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
data-traefik/acme.json
|
||||||
|
.env
|
||||||
7
deploy/all-in-one-traefik/.htpasswd
Normal file
7
deploy/all-in-one-traefik/.htpasswd
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file contains the passwords for the admin panel and tracing.
|
||||||
|
# Change these passwords in production!
|
||||||
|
# default is admin:openmu, hashed with bcrypt.
|
||||||
|
|
||||||
|
admin:$2y$10$xYL2d/QEukwGmX0uNZubsunL0qcANuTYkpapRVdlu5q3ymCpvOEh.
|
||||||
|
|
||||||
|
# this file should always end with an empty line!
|
||||||
140
deploy/all-in-one-traefik/README.md
Normal file
140
deploy/all-in-one-traefik/README.md
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
# All-in-one-traefik deployment
|
||||||
|
|
||||||
|
The all in one (with traefik) deployment is recommended, if you want to host
|
||||||
|
on a small machine with a low amount of players and want to host your
|
||||||
|
MuOnline Website on the same machine.
|
||||||
|
|
||||||
|
Once Traefik works as a Reverse Proxy, you can handle multiple websites
|
||||||
|
without changing the default port to HTTP/HTTPS connections.
|
||||||
|
|
||||||
|
Adding a few labels to your container, you will tell Traefik how to
|
||||||
|
handle incoming requests and it will redirect to the correct website.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
admin-panel:
|
||||||
|
...
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
- "traefik.http.routers.adm.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.adm.rule=Host(`admin.domain.com`)"
|
||||||
|
- "traefik.http.routers.adm.middlewares=auth"
|
||||||
|
- "traefik.http.middlewares.auth.basicauth.usersfile=.htpasswd"
|
||||||
|
|
||||||
|
muonline-website:
|
||||||
|
...
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
- "traefik.http.routers.muonline.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.muonline.rule=Host(`muonline.domain.com`)"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can even add multiple domains and/or subdomains to your host label
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
- "traefik.http.routers.muonline.rule=Host(`www.domain1.com`,`domain1.com`,`sub.domain1.com`)"
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, all kinds of OpenMU subsystems (ConnectServer, GameServer, LoginServer,
|
||||||
|
AdminPanel, ...) are running in one process, but you can run
|
||||||
|
AdminPanel and other websites separately.
|
||||||
|
|
||||||
|
## Deployment with docker-compose
|
||||||
|
|
||||||
|
### Install GIT
|
||||||
|
|
||||||
|
See [https://github.com/git-guides/install-git](https://github.com/git-guides/install-git).
|
||||||
|
|
||||||
|
### Clone the repository
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
git clone https://github.com/MUnique/OpenMU.git
|
||||||
|
```
|
||||||
|
|
||||||
|
It will create a new folder OpenMU with the repository contents inside.
|
||||||
|
|
||||||
|
### Navigate to the docker-compose files
|
||||||
|
|
||||||
|
Navigate to the folder `deploy/all-in-one-traefik`
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
cd deploy/all-in-one-traefik
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create a new docker network
|
||||||
|
|
||||||
|
You need to have communication between containers from different docker compose files
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
docker network create proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option A - for local testing
|
||||||
|
|
||||||
|
To run the official docker image on your local traefik server, just run:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
docker compose -f docker-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
And that's it. It's then available on your local computer through a loopback
|
||||||
|
ip. Your AdminPanel URL is `http://admin.docker.localhost`. You can change it
|
||||||
|
in the `docker-compose.yml` file.
|
||||||
|
|
||||||
|
However, if you want to make it available through the internet, you should choose
|
||||||
|
Option B:
|
||||||
|
|
||||||
|
### Option B - with HTTPS
|
||||||
|
|
||||||
|
If you want to share your server with the world, it's recommended to set up HTTPS
|
||||||
|
and Traefik can handle it for you. Otherwise, traffic from and to the admin
|
||||||
|
panel is not encrypted.
|
||||||
|
|
||||||
|
#### Set your domain name as environment variable
|
||||||
|
|
||||||
|
Make a copy of `.env.example` called `.env` and edit the `.env` file with your
|
||||||
|
domain/subdomain to the AdminPanel URL.
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Make a copy of `data-traefik/acme.example.json` called `data-traefik/acme.json`
|
||||||
|
and apply permission 600 to `acme.json`
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
cp data-traefik/acme.example.json data-traefik/acme.json
|
||||||
|
chmod 600 data-traefik/acme.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Run it
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
docker compose -f docker-compose.prod.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Important
|
||||||
|
|
||||||
|
Avoid editing the .htpasswd manually. Instead, access the admin panel
|
||||||
|
and add a new user. If you are using the _all-in-one-traefik_ you
|
||||||
|
need to restart Traefik after add a new user to it takes effect.
|
||||||
|
|
||||||
|
## What's next
|
||||||
|
|
||||||
|
The server is automatically started and initialized for Season 6. You can start
|
||||||
|
playing, if you want :-)
|
||||||
|
|
||||||
|
Additionally, take a look at the AdminPanel.
|
||||||
|
|
||||||
|
If your containers run on docker at your local machine, you can simply go to `http://admin.docker.localhost/`.
|
||||||
|
The default username is 'admin', the password 'openmu'. You should change that later.
|
||||||
|
|
||||||
|
If you want to run another game version, you can go to the setup page through
|
||||||
|
the navigation menu, where you can select your desired game version,
|
||||||
|
number of game servers (just the data of it), and if test accounts
|
||||||
|
should be created.
|
||||||
|
|
||||||
|
If you click on 'Install', wait a bit until the database is set up and
|
||||||
|
filled with the data and voila, OpenMU is ready to use.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Dynamic configuration
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
nofloc:
|
||||||
|
headers:
|
||||||
|
customResponseHeaders:
|
||||||
|
Permissions-Policy: "interest-cohort=()"
|
||||||
|
secureHeaders:
|
||||||
|
headers:
|
||||||
|
sslRedirect: true
|
||||||
|
forceSTSHeader: true
|
||||||
|
stsIncludeSubdomains: true
|
||||||
|
stsPreload: true
|
||||||
|
stsSeconds: 31536000
|
||||||
|
|
||||||
|
tls:
|
||||||
|
options:
|
||||||
|
default:
|
||||||
|
cipherSuites:
|
||||||
|
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
||||||
|
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||||
|
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||||
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
|
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
|
||||||
|
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||||
|
minVersion: VersionTLS12
|
||||||
47
deploy/all-in-one-traefik/data-traefik/traefik.yml
Normal file
47
deploy/all-in-one-traefik/data-traefik/traefik.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
api:
|
||||||
|
dashboard: true
|
||||||
|
|
||||||
|
entryPoints:
|
||||||
|
web:
|
||||||
|
address: :80
|
||||||
|
http:
|
||||||
|
redirections:
|
||||||
|
entryPoint:
|
||||||
|
to: websecure
|
||||||
|
|
||||||
|
websecure:
|
||||||
|
address: :443
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
- secureHeaders@file
|
||||||
|
- nofloc@file
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
pilot:
|
||||||
|
dashboard: false
|
||||||
|
|
||||||
|
providers:
|
||||||
|
docker:
|
||||||
|
endpoint: "unix:///var/run/docker.sock"
|
||||||
|
exposedByDefault: false
|
||||||
|
file:
|
||||||
|
filename: /configurations/dynamic.yml
|
||||||
|
|
||||||
|
certificatesResolvers:
|
||||||
|
letsencrypt:
|
||||||
|
acme:
|
||||||
|
email: admin@domain.com
|
||||||
|
storage: acme.json
|
||||||
|
keyType: EC384
|
||||||
|
httpChallenge:
|
||||||
|
entryPoint: web
|
||||||
|
|
||||||
|
buypass:
|
||||||
|
acme:
|
||||||
|
email: admin@domain.com
|
||||||
|
storage: acme.json
|
||||||
|
caServer: https://api.buypass.com/acme/directory
|
||||||
|
keyType: EC256
|
||||||
|
httpChallenge:
|
||||||
|
entryPoint: web
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectVersion>2.1</ProjectVersion>
|
||||||
|
<DockerTargetOS>Linux</DockerTargetOS>
|
||||||
|
<ProjectGuid>4430d6a8-54b5-412b-9dba-07b3e3580af7</ProjectGuid>
|
||||||
|
<DockerLaunchAction>None</DockerLaunchAction>
|
||||||
|
<DockerServiceUrl>{Scheme}://localhost:{ServicePort}</DockerServiceUrl>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<DockerServiceName>openmu-startup-traefik</DockerServiceName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include=".env.example" />
|
||||||
|
<None Include="docker-compose.yml">
|
||||||
|
</None>
|
||||||
|
<None Include="docker-compose.prod.yml">
|
||||||
|
</None>
|
||||||
|
<None Include=".dockerignore" />
|
||||||
|
<None Include=".gitignore" />
|
||||||
|
<None Include=".htpasswd" />
|
||||||
|
<None Include="README.md" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
71
deploy/all-in-one-traefik/docker-compose.prod.yml
Normal file
71
deploy/all-in-one-traefik/docker-compose.prod.yml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
services:
|
||||||
|
openmu-startup:
|
||||||
|
image: munique/openmu
|
||||||
|
container_name: openmu-startup
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
ports:
|
||||||
|
- "55901:55901"
|
||||||
|
- "55902:55902"
|
||||||
|
- "55903:55903"
|
||||||
|
- "55904:55904"
|
||||||
|
- "55905:55905"
|
||||||
|
- "55906:55906"
|
||||||
|
- "44405:44405"
|
||||||
|
- "55980:55980"
|
||||||
|
environment:
|
||||||
|
DB_HOST: database
|
||||||
|
working_dir: /app/
|
||||||
|
volumes:
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
- "traefik.http.routers.openmu.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.openmu.rule=Host(`${DOMAIN}`)"
|
||||||
|
- "traefik.http.routers.openmu.middlewares=auth"
|
||||||
|
- "traefik.http.middlewares.auth.basicauth.usersfile=.htpasswd"
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: postgres
|
||||||
|
container_name: database
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: admin
|
||||||
|
POSTGRES_DB: openmu
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
ports:
|
||||||
|
- "5432"
|
||||||
|
volumes:
|
||||||
|
- dbdata:/var/lib/postgresql #store data on volume
|
||||||
|
|
||||||
|
traefik:
|
||||||
|
image: traefik
|
||||||
|
container_name: traefik
|
||||||
|
restart: always
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
- 443:443
|
||||||
|
volumes:
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- ./data-traefik/traefik.yml:/traefik.yml:ro
|
||||||
|
- ./data-traefik/acme.json:/acme.json
|
||||||
|
- ./data-traefik/configurations:/configurations
|
||||||
|
- "./.htpasswd:/.htpasswd"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
dbdata:
|
||||||
68
deploy/all-in-one-traefik/docker-compose.yml
Normal file
68
deploy/all-in-one-traefik/docker-compose.yml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
services:
|
||||||
|
openmu-startup:
|
||||||
|
image: munique/openmu
|
||||||
|
container_name: openmu-startup
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
ports:
|
||||||
|
- "55901:55901"
|
||||||
|
- "55902:55902"
|
||||||
|
- "55903:55903"
|
||||||
|
- "55904:55904"
|
||||||
|
- "55905:55905"
|
||||||
|
- "55906:55906"
|
||||||
|
- "44405:44405"
|
||||||
|
- "55980:55980"
|
||||||
|
environment:
|
||||||
|
DB_HOST: database
|
||||||
|
working_dir: /app/
|
||||||
|
volumes:
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
- "traefik.http.routers.openmu.entrypoints=web"
|
||||||
|
- "traefik.http.routers.openmu.rule=Host(`admin.docker.localhost`)"
|
||||||
|
- "traefik.http.routers.openmu.middlewares=auth"
|
||||||
|
- "traefik.http.middlewares.auth.basicauth.usersfile=.htpasswd"
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: postgres
|
||||||
|
container_name: database
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: admin
|
||||||
|
POSTGRES_DB: openmu
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- dbdata:/var/lib/postgresql #store data on volume
|
||||||
|
|
||||||
|
traefik:
|
||||||
|
image: "traefik"
|
||||||
|
container_name: "traefik"
|
||||||
|
restart: always
|
||||||
|
command:
|
||||||
|
- "--log.level=DEBUG"
|
||||||
|
- "--api.insecure=true"
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||||
|
- "./.htpasswd:/.htpasswd"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
dbdata:
|
||||||
25
deploy/all-in-one/.dockerignore
Normal file
25
deploy/all-in-one/.dockerignore
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
7
deploy/all-in-one/.htpasswd
Normal file
7
deploy/all-in-one/.htpasswd
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file contains the passwords for the admin panel and tracing.
|
||||||
|
# Change these passwords in production!
|
||||||
|
# default is admin:openmu, hashed with bcrypt.
|
||||||
|
|
||||||
|
admin:$2y$10$xYL2d/QEukwGmX0uNZubsunL0qcANuTYkpapRVdlu5q3ymCpvOEh.
|
||||||
|
|
||||||
|
# this file should always end with an empty line!
|
||||||
89
deploy/all-in-one/README.md
Normal file
89
deploy/all-in-one/README.md
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# All-in-one deployment
|
||||||
|
|
||||||
|
The all in one deployment is recommended, if you want to host on a small machine
|
||||||
|
with a low amount of players.
|
||||||
|
|
||||||
|
In this case, all kinds of OpenMU subsystems (ConnectServer, GameServer, LoginServer,
|
||||||
|
AdminPanel, ...) are running in one process.
|
||||||
|
|
||||||
|
## Deployment with docker-compose
|
||||||
|
|
||||||
|
### Install GIT
|
||||||
|
|
||||||
|
See [https://github.com/git-guides/install-git](https://github.com/git-guides/install-git).
|
||||||
|
|
||||||
|
### Clone the repository
|
||||||
|
|
||||||
|
`git clone https://github.com/MUnique/OpenMU.git`
|
||||||
|
|
||||||
|
It will create a new folder OpenMU with the repository contents inside.
|
||||||
|
|
||||||
|
### Navigate to the docker-compose files
|
||||||
|
|
||||||
|
Navigate to the folder deploy/all-in-one
|
||||||
|
|
||||||
|
`cd deploy/all-in-one`
|
||||||
|
|
||||||
|
### Option A - for local testing
|
||||||
|
|
||||||
|
To use the official docker image, just run:
|
||||||
|
|
||||||
|
`docker compose up -d --no-build`
|
||||||
|
|
||||||
|
And that's it. It's then available on your local computer through a loopback ip.
|
||||||
|
|
||||||
|
However, if you want to make it available through the internet, you should choose
|
||||||
|
Option B:
|
||||||
|
|
||||||
|
### Option B - with HTTPS
|
||||||
|
|
||||||
|
If you want to share your server with the world, it's recommended to set up HTTPS
|
||||||
|
for nginx. Otherwise, traffic from and to the admin panel is not encrypted.
|
||||||
|
|
||||||
|
#### Set your domain name as environment variable
|
||||||
|
|
||||||
|
Specify the environment variable ```DOMAIN_NAME``` for docker compose.
|
||||||
|
This can be done in [various ways](https://docs.docker.com/compose/environment-variables/set-environment-variables/),
|
||||||
|
e.g. by editing the ```docker-compose.prod.yml``` or
|
||||||
|
[setting it in your shell](https://phoenixnap.com/kb/linux-set-environment-variable).
|
||||||
|
|
||||||
|
This variable is replaced in the nginx template config files which get included
|
||||||
|
in the other configuration files.
|
||||||
|
|
||||||
|
#### Run it
|
||||||
|
|
||||||
|
`docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d`
|
||||||
|
|
||||||
|
#### Run certbot explicitly
|
||||||
|
|
||||||
|
Hint: replace "example.org" with your domain.
|
||||||
|
|
||||||
|
`docker compose -f docker-compose.yml -f docker-compose.prod.yml run --rm certbot certonly --webroot --webroot-path /var/www/certbot/ -d example.org`
|
||||||
|
|
||||||
|
#### Set up certificate renewal
|
||||||
|
|
||||||
|
Because your certificates expire after 3 months, it's recommended to renew them regularly.
|
||||||
|
To renew it, run this command:
|
||||||
|
|
||||||
|
`docker compose -f docker-compose.yml -f docker-compose.prod.yml run --rm certbot renew`
|
||||||
|
|
||||||
|
Of course, it would make sense to add a cron job (e.g. once a week) on your host
|
||||||
|
machine for that.
|
||||||
|
|
||||||
|
## What's next
|
||||||
|
|
||||||
|
The server is automatically started and initialized for Season 6. You can start
|
||||||
|
playing, if you want :-)
|
||||||
|
|
||||||
|
Additionally, take a look at the AdminPanel.
|
||||||
|
|
||||||
|
If your containers run on docker at your local machine, you can simply go to `http://localhost/`.
|
||||||
|
The default username is 'admin', the password 'openmu'. You should change that later.
|
||||||
|
|
||||||
|
If you want to run another game version, you can go to the setup page through
|
||||||
|
the navigation menu, where you can select your desired game version,
|
||||||
|
number of game servers (just the data of it), and if test accounts
|
||||||
|
should be created.
|
||||||
|
|
||||||
|
If you click on 'Install', wait a bit until the database is set up and filled with the
|
||||||
|
data and voila, OpenMU is ready to use.
|
||||||
30
deploy/all-in-one/docker-compose-all-in-one.dcproj
Normal file
30
deploy/all-in-one/docker-compose-all-in-one.dcproj
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectVersion>2.1</ProjectVersion>
|
||||||
|
<DockerTargetOS>Linux</DockerTargetOS>
|
||||||
|
<ProjectGuid>6518d58a-5f07-4341-87af-fcf3715d2554</ProjectGuid>
|
||||||
|
<DockerLaunchAction>None</DockerLaunchAction>
|
||||||
|
<DockerServiceUrl>{Scheme}://localhost:{ServicePort}</DockerServiceUrl>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<DockerServiceName>openmu-startup</DockerServiceName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="docker-compose.override.yml">
|
||||||
|
<DependentUpon>docker-compose.yml</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="docker-compose.prod.yml">
|
||||||
|
<DependentUpon>docker-compose.yml</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="docker-compose.yml" />
|
||||||
|
<None Include=".dockerignore" />
|
||||||
|
<None Include=".htpasswd" />
|
||||||
|
<None Include="nginx\nginx.dev.conf" />
|
||||||
|
<None Include="nginx\nginx.prod443.conf" />
|
||||||
|
<None Include="nginx\nginx.prod80.conf" />
|
||||||
|
<None Include="nginx\templates\nginx.prod.certificates.conf.template" />
|
||||||
|
<None Include="nginx\templates\nginx.server_name.conf.template" />
|
||||||
|
<None Include="README.md" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
13
deploy/all-in-one/docker-compose.override.yml
Normal file
13
deploy/all-in-one/docker-compose.override.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
services:
|
||||||
|
|
||||||
|
openmu-startup:
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Startup/Dockerfile
|
||||||
|
restart: "no"
|
||||||
|
ports:
|
||||||
|
- "8081:8080"
|
||||||
|
|
||||||
|
database:
|
||||||
|
ports:
|
||||||
|
- "5433:5432"
|
||||||
46
deploy/all-in-one/docker-compose.prod.yml
Normal file
46
deploy/all-in-one/docker-compose.prod.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
services:
|
||||||
|
openmu-startup:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
|
|
||||||
|
database:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
|
||||||
|
nginx-80:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
DOMAIN_NAME: ${DOMAIN_NAME}
|
||||||
|
volumes:
|
||||||
|
- ./nginx/nginx.prod80.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
- ./certbot/www:/var/www/certbot/:ro
|
||||||
|
- ./nginx/templates/nginx.server_name.conf.template:/etc/nginx/templates/nginx.server_name.conf.template:ro
|
||||||
|
|
||||||
|
# We add another nginx here, just for HTTPs.
|
||||||
|
# The reason is, that it's not starting when we combine port 80 and 443 until
|
||||||
|
# the certificates are created.
|
||||||
|
# So, when running the certbot the first time, we need to be able to access
|
||||||
|
# the port 80 - and we solve this by separating the server configs.
|
||||||
|
nginx-443:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: nginx-443
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
DOMAIN_NAME: ${DOMAIN_NAME}
|
||||||
|
ports:
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx/nginx.prod443.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
- ./certbot/conf/:/etc/nginx/ssl/:ro
|
||||||
|
- ./nginx/templates/nginx.server_name.conf.template:/etc/nginx/templates/nginx.server_name.conf.template:ro
|
||||||
|
- ./nginx/templates/nginx.prod.certificates.conf.template:/etc/nginx/templates/nginx.prod.certificates.conf.template:ro
|
||||||
|
depends_on:
|
||||||
|
- openmu-startup
|
||||||
|
|
||||||
|
certbot:
|
||||||
|
image: certbot/certbot:latest
|
||||||
|
volumes:
|
||||||
|
- ./certbot/www/:/var/www/certbot/:rw
|
||||||
|
- ./certbot/conf/:/etc/letsencrypt/:rw
|
||||||
49
deploy/all-in-one/docker-compose.yml
Normal file
49
deploy/all-in-one/docker-compose.yml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
services:
|
||||||
|
nginx-80:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: nginx-80
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- ./nginx/nginx.dev.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
depends_on:
|
||||||
|
- openmu-startup
|
||||||
|
|
||||||
|
openmu-startup:
|
||||||
|
image: munique/openmu
|
||||||
|
container_name: openmu-startup
|
||||||
|
ports:
|
||||||
|
- "8080"
|
||||||
|
- "55901:55901"
|
||||||
|
- "55902:55902"
|
||||||
|
- "55903:55903"
|
||||||
|
- "55904:55904"
|
||||||
|
- "55905:55905"
|
||||||
|
- "55906:55906"
|
||||||
|
- "44405:44405"
|
||||||
|
- "44406:44406"
|
||||||
|
- "55980:55980"
|
||||||
|
environment:
|
||||||
|
DB_HOST: database
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
working_dir: /app/
|
||||||
|
volumes:
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: postgres
|
||||||
|
container_name: database
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: admin
|
||||||
|
POSTGRES_DB: openmu
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
ports:
|
||||||
|
- "5432"
|
||||||
|
volumes:
|
||||||
|
- dbdata:/var/lib/postgresql #store data on volume
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
dbdata:
|
||||||
26
deploy/all-in-one/nginx/nginx.dev.conf
Normal file
26
deploy/all-in-one/nginx/nginx.dev.conf
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
events {
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
# this is required to proxy Grafana Live WebSocket connections.
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
auth_basic "Protected Site";
|
||||||
|
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://openmu-startup:8080;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
deploy/all-in-one/nginx/nginx.prod443.conf
Normal file
32
deploy/all-in-one/nginx/nginx.prod443.conf
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
events {
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
# this is required to proxy Grafana Live WebSocket connections.
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 default_server ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
|
||||||
|
include conf.d/nginx.server_name.conf;
|
||||||
|
include conf.d/nginx.prod.certificates.conf;
|
||||||
|
|
||||||
|
auth_basic "Protected Site";
|
||||||
|
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://openmu-startup:8080;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
deploy/all-in-one/nginx/nginx.prod80.conf
Normal file
20
deploy/all-in-one/nginx/nginx.prod80.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
events {
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
include conf.d/nginx.server_name.conf;
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ssl_certificate /etc/nginx/ssl/live/$DOMAIN_NAME/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/live/$DOMAIN_NAME/privkey.pem;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
server_name $DOMAIN_NAME;
|
||||||
25
deploy/distributed/.dockerignore
Normal file
25
deploy/distributed/.dockerignore
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
7
deploy/distributed/.htpasswd
Normal file
7
deploy/distributed/.htpasswd
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file contains the passwords for the admin panel and tracing.
|
||||||
|
# Change these passwords in production!
|
||||||
|
# default is admin:openmu, hashed with bcrypt.
|
||||||
|
|
||||||
|
admin:$2y$10$xYL2d/QEukwGmX0uNZubsunL0qcANuTYkpapRVdlu5q3ymCpvOEh.
|
||||||
|
|
||||||
|
# this file should always end with an empty line!
|
||||||
121
deploy/distributed/README.md
Normal file
121
deploy/distributed/README.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# Distributed
|
||||||
|
|
||||||
|
*!!! CURRENTLY BROKEN AND UNSUPPORTED, DOCS ARE OUT OF DATE !!!*
|
||||||
|
|
||||||
|
## Deployment with docker-compose
|
||||||
|
|
||||||
|
Currently, we just have a docker-compose file for the deployment.
|
||||||
|
docker-compose has the limitation, that all runs on the same physical machine.
|
||||||
|
|
||||||
|
For an even more distributed environment, with more machines, kubernetes can be
|
||||||
|
used. However, we don't have a finished configuration for kubernetes, yet. If you
|
||||||
|
are familiar with kubernetes, all contributions are welcome for kubernetes
|
||||||
|
configuration files.
|
||||||
|
|
||||||
|
So, these are the steps, if you want to deploy it with docker-compose:
|
||||||
|
|
||||||
|
### Install GIT
|
||||||
|
|
||||||
|
See [https://github.com/git-guides/install-git](https://github.com/git-guides/install-git).
|
||||||
|
|
||||||
|
### Clone the repository
|
||||||
|
|
||||||
|
`git clone https://github.com/MUnique/OpenMU.git`
|
||||||
|
|
||||||
|
It will create a new folder OpenMU with the repository contents inside.
|
||||||
|
|
||||||
|
### Navigate to the docker-compose files
|
||||||
|
|
||||||
|
Navigate to the folder deploy/distributed
|
||||||
|
|
||||||
|
`cd deploy/distributed`
|
||||||
|
|
||||||
|
### Option A - for local testing
|
||||||
|
|
||||||
|
To use the official docker images, just run:
|
||||||
|
|
||||||
|
`docker compose up -d --no-build`
|
||||||
|
|
||||||
|
And that's it. It's then available on your local computer through a loopback ip.
|
||||||
|
|
||||||
|
However, if you want to make it available through the internet, you should choose
|
||||||
|
Option B:
|
||||||
|
|
||||||
|
### Option B - with HTTPS
|
||||||
|
|
||||||
|
If you want to share your server with the world, it's recommended to set up HTTPS
|
||||||
|
for nginx. Otherwise, traffic from and to the admin panel is not encrypted.
|
||||||
|
|
||||||
|
#### Set your domain name as environment variable
|
||||||
|
|
||||||
|
Specify the environment variable ```DOMAIN_NAME``` for docker compose.
|
||||||
|
This can be done in [various ways](https://docs.docker.com/compose/environment-variables/set-environment-variables/),
|
||||||
|
e.g. by editing the ```docker-compose.prod.yml``` or
|
||||||
|
[setting it in your shell](https://phoenixnap.com/kb/linux-set-environment-variable).
|
||||||
|
|
||||||
|
This variable is replaced in the nginx template config files which get included
|
||||||
|
in the other configuration files.
|
||||||
|
|
||||||
|
#### Run it
|
||||||
|
|
||||||
|
`docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d`
|
||||||
|
|
||||||
|
#### Run certbot explicitly
|
||||||
|
|
||||||
|
Hint: replace "example.org" with your domain.
|
||||||
|
|
||||||
|
`docker compose -f docker-compose.yml -f docker-compose.prod.yml run --rm certbot certonly --webroot --webroot-path /var/www/certbot/ -d example.org`
|
||||||
|
|
||||||
|
#### Set up certificate renewal
|
||||||
|
|
||||||
|
Because your certificates expire after 3 months, it's recommended to renew them regularly.
|
||||||
|
To renew it, run this command:
|
||||||
|
|
||||||
|
`docker compose -f docker-compose.yml -f docker-compose.prod.yml run --rm certbot renew`
|
||||||
|
|
||||||
|
Of course, it would make sense to add a cron job (e.g. once a week) on your host
|
||||||
|
machine for that.
|
||||||
|
|
||||||
|
## What's next
|
||||||
|
|
||||||
|
Now, when you have deployed OpenMU, it's time to discover the AdminPanel.
|
||||||
|
|
||||||
|
If your containers run on docker at your local machine, you can simply go to `http://localhost/admin`.
|
||||||
|
The default username is 'admin', the password 'openmu'. You should change that later.
|
||||||
|
|
||||||
|
There you'll find a setup in the navigation menu, where you can select your desired
|
||||||
|
game version, number of game servers (just the data of it), and if test accounts
|
||||||
|
should be created.
|
||||||
|
|
||||||
|
Click on 'Install', wait a bit until the database is set up and filled with the
|
||||||
|
data.
|
||||||
|
OpenMU should now be ready to use.
|
||||||
|
|
||||||
|
## Environment variables
|
||||||
|
|
||||||
|
The openmu images which are used in this docker-compose consider the following
|
||||||
|
environment variables:
|
||||||
|
|
||||||
|
### ASPNETCORE_ENVIRONMENT
|
||||||
|
|
||||||
|
It's usually specified correctly in the docker-compose files. It has effect on
|
||||||
|
the ip resolver, see below.
|
||||||
|
|
||||||
|
### RESOLVE_IP
|
||||||
|
|
||||||
|
Similar to the -resolveIp starting parameter of the all-in-one startup project,
|
||||||
|
you're able to control the ip resolving with this variable. The defaults usually
|
||||||
|
work fine here, so you should try not to set this variable.
|
||||||
|
|
||||||
|
| Value | Description |
|
||||||
|
|-------|---------------------|
|
||||||
|
| local | Default value in a *Development* environment. Determines a local ip. If none is found, a loopback IP is used (127.127.127.127). |
|
||||||
|
| public | Default value in a *Production* environment. The public ip is automatically determined by an [external API](https://www.ipify.org/). |
|
||||||
|
| loopback | Returns *127.127.127.127*, usefully only if you run your server and client on the same machine. |
|
||||||
|
| [custom ip] | You can specify a custom ip, if needed. Example: *192.168.0.1* |
|
||||||
|
|
||||||
|
### GS_ID
|
||||||
|
|
||||||
|
It's usually specified correctly in the docker-compose files or each game server.
|
||||||
|
Specifies the id of a game server, and is used to retrieve the GameServerConfiguration
|
||||||
|
from the database.
|
||||||
11
deploy/distributed/dapr-components/config.yaml
Normal file
11
deploy/distributed/dapr-components/config.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: dapr.io/v1alpha1
|
||||||
|
kind: Configuration
|
||||||
|
metadata:
|
||||||
|
name: daprConfig
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
tracing:
|
||||||
|
enabled: true
|
||||||
|
samplingRate: "1"
|
||||||
|
zipkin:
|
||||||
|
endpointAddress: "http://zipkin:9411/api/v2/spans"
|
||||||
13
deploy/distributed/dapr-components/localSecretStore.yaml
Normal file
13
deploy/distributed/dapr-components/localSecretStore.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: dapr.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: secrets
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
type: secretstores.local.file
|
||||||
|
version: v1
|
||||||
|
metadata:
|
||||||
|
- name: secretsFile
|
||||||
|
value: components/secrets.json
|
||||||
|
- name: nestedSeparator
|
||||||
|
value: ":"
|
||||||
13
deploy/distributed/dapr-components/login-state.yaml
Normal file
13
deploy/distributed/dapr-components/login-state.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: dapr.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: login-state
|
||||||
|
spec:
|
||||||
|
spec:
|
||||||
|
type: state.redis
|
||||||
|
version: v1
|
||||||
|
metadata:
|
||||||
|
- name: redisHost
|
||||||
|
value: redis-state:6379
|
||||||
|
#- name: ttlInSeconds
|
||||||
|
# value: <int> # Optional
|
||||||
20
deploy/distributed/dapr-components/pubsub.yaml
Normal file
20
deploy/distributed/dapr-components/pubsub.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: dapr.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: pubsub
|
||||||
|
spec:
|
||||||
|
type: pubsub.rabbitmq
|
||||||
|
version: v1
|
||||||
|
metadata:
|
||||||
|
- name: host
|
||||||
|
value: "amqp://rabbit:5672"
|
||||||
|
- name: durable
|
||||||
|
value: "true"
|
||||||
|
- name: deletedWhenUnused
|
||||||
|
value: "false"
|
||||||
|
- name: autoAck
|
||||||
|
value: "false"
|
||||||
|
- name: reconnectWait
|
||||||
|
value: "0"
|
||||||
|
- name: concurrency
|
||||||
|
value: parallel
|
||||||
11
deploy/distributed/dapr-components/secrets.json
Normal file
11
deploy/distributed/dapr-components/secrets.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"connectionStrings": {
|
||||||
|
"MUnique.OpenMU.Persistence.EntityFramework.EntityDataContext": "Server=database;Port=5432;User Id=postgres;Password=admin;Database=openmu;Command Timeout=120;",
|
||||||
|
"MUnique.OpenMU.Persistence.EntityFramework.TypedContext": "Server=database;Port=5432;User Id=postgres;Password=admin;Database=openmu;Command Timeout=120;",
|
||||||
|
"MUnique.OpenMU.Persistence.EntityFramework.ConfigurationContext": "Server=database;Port=5432;User Id=config;Password=config;Database=openmu;Command Timeout=120;",
|
||||||
|
"MUnique.OpenMU.Persistence.EntityFramework.AccountContext": "Server=database;Port=5432;User Id=account;Password=account;Database=openmu;Command Timeout=120;",
|
||||||
|
"MUnique.OpenMU.Persistence.EntityFramework.TradeContext": "Server=database;Port=5432;User Id=account;Password=account;Database=openmu;Command Timeout=120;",
|
||||||
|
"MUnique.OpenMU.Persistence.EntityFramework.FriendContext": "Server=database;Port=5432;User Id=friend;Password=friend;Database=openmu;Command Timeout=120;",
|
||||||
|
"MUnique.OpenMU.Persistence.EntityFramework.GuildContext": "Server=database;Port=5432;User Id=guild;Password=guild;Database=openmu;Command Timeout=120;"
|
||||||
|
}
|
||||||
|
}
|
||||||
39
deploy/distributed/docker-compose.dcproj
Normal file
39
deploy/distributed/docker-compose.dcproj
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectVersion>2.1</ProjectVersion>
|
||||||
|
<DockerTargetOS>Linux</DockerTargetOS>
|
||||||
|
<ProjectGuid>0dfecd55-7aa2-4263-b6fd-ec1c4e6a59b3</ProjectGuid>
|
||||||
|
<DockerLaunchAction>None</DockerLaunchAction>
|
||||||
|
<DockerServiceUrl>{Scheme}://localhost:{ServicePort}</DockerServiceUrl>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<DockerServiceName>openmu-distributed</DockerServiceName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="dapr-components\config.yaml" />
|
||||||
|
<None Include="dapr-components\localSecretStore.yaml" />
|
||||||
|
<None Include="dapr-components\login-state.yaml" />
|
||||||
|
<None Include="dapr-components\pubsub.yaml" />
|
||||||
|
<None Include="dapr-components\secrets.json" />
|
||||||
|
<None Include="docker-compose.override.yml">
|
||||||
|
<DependentUpon>docker-compose.yml</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="docker-compose.prod.yml">
|
||||||
|
<DependentUpon>docker-compose.yml</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="docker-compose.yml" />
|
||||||
|
<None Include=".dockerignore" />
|
||||||
|
<None Include=".htpasswd" />
|
||||||
|
<None Include="grafana.ini" />
|
||||||
|
<None Include="grafana_datasources.yaml" />
|
||||||
|
<None Include="loki-config.yaml" />
|
||||||
|
<None Include="nginx.prod.certificates.conf.template" />
|
||||||
|
<None Include="nginx.server_name.conf.template" />
|
||||||
|
<None Include="nginx.prod80.conf" />
|
||||||
|
<None Include="nginx.prod443.conf" />
|
||||||
|
<None Include="nginx.dev.conf" />
|
||||||
|
<None Include="prometheus.yml" />
|
||||||
|
<None Include="README.md" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
70
deploy/distributed/docker-compose.override.yml
Normal file
70
deploy/distributed/docker-compose.override.yml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
services:
|
||||||
|
database:
|
||||||
|
ports:
|
||||||
|
- "5433:5432"
|
||||||
|
loki:
|
||||||
|
ports:
|
||||||
|
- "3100:3100"
|
||||||
|
prometheus:
|
||||||
|
ports:
|
||||||
|
- "9000:9090"
|
||||||
|
|
||||||
|
redis-state:
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
|
||||||
|
gameServer0:
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Development
|
||||||
|
ports:
|
||||||
|
- "81:8080"
|
||||||
|
|
||||||
|
gameServer1:
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Development
|
||||||
|
ports:
|
||||||
|
- "82:8080"
|
||||||
|
|
||||||
|
connectServer:
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Dapr/ConnectServer.Host/Dockerfile
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Development
|
||||||
|
|
||||||
|
loginServer:
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Dapr/LoginServer.Host/Dockerfile
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Development
|
||||||
|
|
||||||
|
friendServer:
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Dapr/FriendServer.Host/Dockerfile
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Development
|
||||||
|
|
||||||
|
guildServer:
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Dapr/GuildServer.Host/Dockerfile
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Development
|
||||||
|
|
||||||
|
chatServer:
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Dapr/ChatServer.Host/Dockerfile
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Development
|
||||||
|
|
||||||
|
adminPanel:
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Dapr/AdminPanel.Host/Dockerfile
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Development
|
||||||
|
ports:
|
||||||
|
- "88:8080"
|
||||||
103
deploy/distributed/docker-compose.prod.yml
Normal file
103
deploy/distributed/docker-compose.prod.yml
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
volumes:
|
||||||
|
certificates:
|
||||||
|
certbot-www:
|
||||||
|
|
||||||
|
services:
|
||||||
|
nginx-80:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
DOMAIN_NAME: ${DOMAIN_NAME}
|
||||||
|
volumes:
|
||||||
|
- ./nginx.server_name.conf.template:/etc/nginx/templates/nginx.server_name.conf.template
|
||||||
|
- ./nginx.prod80.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
- certbot-www:/var/www/certbot/:ro
|
||||||
|
|
||||||
|
# We add another nginx here, just for HTTPs.
|
||||||
|
# The reason is, that it's not starting when we combine port 80 and 443 until
|
||||||
|
# the certificates are created.
|
||||||
|
# So, when running the certbot the first time, we need to be able to access
|
||||||
|
# the port 80 - and we solve this by separating the server configs.
|
||||||
|
nginx-443:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: nginx-443
|
||||||
|
restart: "unless-stopped"
|
||||||
|
ports:
|
||||||
|
- "443:443"
|
||||||
|
environment:
|
||||||
|
DOMAIN_NAME: ${DOMAIN_NAME}
|
||||||
|
volumes:
|
||||||
|
- ./nginx.server_name.conf.template:/etc/nginx/templates/nginx.server_name.conf.template
|
||||||
|
- ./nginx.prod.certificates.conf.template:/etc/nginx/templates/nginx.prod.certificates.conf.template
|
||||||
|
- ./nginx.prod443.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
- certificates:/etc/nginx/ssl/:ro
|
||||||
|
depends_on:
|
||||||
|
- grafana
|
||||||
|
- zipkin
|
||||||
|
- prometheus
|
||||||
|
|
||||||
|
certbot:
|
||||||
|
image: certbot/certbot:latest
|
||||||
|
volumes:
|
||||||
|
- certbot-www:/var/www/certbot/:rw
|
||||||
|
- certificates:/etc/letsencrypt/:rw
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
prometheus:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
loki:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
minio:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
redis-state:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
dapr-placement:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
rabbit:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
database:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
zipkin:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
|
||||||
|
connectServer:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
|
|
||||||
|
loginServer:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
|
|
||||||
|
friendServer:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
|
|
||||||
|
guildServer:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
|
|
||||||
|
chatServer:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
|
|
||||||
|
adminPanel:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
|
|
||||||
|
gameServer0:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
|
|
||||||
|
gameServer1:
|
||||||
|
restart: "unless-stopped"
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
352
deploy/distributed/docker-compose.yml
Normal file
352
deploy/distributed/docker-compose.yml
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
volumes:
|
||||||
|
dbdata:
|
||||||
|
prometheus-data:
|
||||||
|
minio-data:
|
||||||
|
|
||||||
|
services:
|
||||||
|
nginx-80:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: nginx-80
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- ./nginx.dev.conf:/etc/nginx/nginx.conf
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
depends_on:
|
||||||
|
- grafana
|
||||||
|
- zipkin
|
||||||
|
- prometheus
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana:9.5.14
|
||||||
|
container_name: grafana
|
||||||
|
volumes:
|
||||||
|
- ./grafana.ini:/etc/grafana/grafana.ini
|
||||||
|
- ./grafana_datasources.yaml:/etc/grafana/provisioning/datasources/ds.yaml
|
||||||
|
depends_on:
|
||||||
|
- loki
|
||||||
|
- prometheus
|
||||||
|
ports:
|
||||||
|
- 3000
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
image: prom/prometheus:v2.21.0
|
||||||
|
ports:
|
||||||
|
- 9090
|
||||||
|
volumes:
|
||||||
|
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
|
- prometheus-data:/prometheus
|
||||||
|
command: --web.enable-lifecycle --config.file=/etc/prometheus/prometheus.yml
|
||||||
|
|
||||||
|
loki:
|
||||||
|
image: grafana/loki:2.5.0
|
||||||
|
container_name: loki
|
||||||
|
command: "-config.file=/etc/loki/config.yaml -target=all"
|
||||||
|
ports:
|
||||||
|
- 3100
|
||||||
|
- 7946
|
||||||
|
- 9095
|
||||||
|
volumes:
|
||||||
|
- ./loki-config.yaml:/etc/loki/config.yaml
|
||||||
|
depends_on:
|
||||||
|
- minio
|
||||||
|
|
||||||
|
minio:
|
||||||
|
image: minio/minio
|
||||||
|
entrypoint:
|
||||||
|
- sh
|
||||||
|
- -euc
|
||||||
|
- |
|
||||||
|
mkdir -p /data/loki-data && \
|
||||||
|
mkdir -p /data/loki-ruler && \
|
||||||
|
minio server /data
|
||||||
|
environment:
|
||||||
|
- MINIO_ACCESS_KEY=loki
|
||||||
|
- MINIO_SECRET_KEY=supersecret
|
||||||
|
- MINIO_PROMETHEUS_AUTH_TYPE=public
|
||||||
|
- MINIO_UPDATE=off
|
||||||
|
ports:
|
||||||
|
- 9000
|
||||||
|
volumes:
|
||||||
|
- minio-data:/data
|
||||||
|
|
||||||
|
redis-state:
|
||||||
|
image: redis
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 6379
|
||||||
|
environment:
|
||||||
|
ALLOW_EMPTY_PASSWORD: "yes"
|
||||||
|
|
||||||
|
dapr-placement:
|
||||||
|
image: "daprio/dapr"
|
||||||
|
container_name: dapr_placement
|
||||||
|
command: ["./placement", "-port", "50006"]
|
||||||
|
ports:
|
||||||
|
- "50006"
|
||||||
|
|
||||||
|
rabbit:
|
||||||
|
image: rabbitmq:3-management-alpine
|
||||||
|
container_name: pubsub_rabbitmq
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "5672"
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: postgres
|
||||||
|
container_name: postgres
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: admin
|
||||||
|
POSTGRES_DB: openmu
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
ports:
|
||||||
|
- "5432"
|
||||||
|
volumes:
|
||||||
|
- dbdata:/var/lib/postgresql
|
||||||
|
|
||||||
|
zipkin:
|
||||||
|
image: openzipkin/zipkin
|
||||||
|
container_name: tracing_zipkin
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "9411:9411"
|
||||||
|
|
||||||
|
connectServer:
|
||||||
|
image: munique/openmu-connect
|
||||||
|
container_name: connectServer
|
||||||
|
ports:
|
||||||
|
- "50001"
|
||||||
|
- "44405:44405"
|
||||||
|
- "9464" # Prometheus
|
||||||
|
environment:
|
||||||
|
APPID: connectServer
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
- zipkin
|
||||||
|
- database
|
||||||
|
|
||||||
|
connectServer-dapr:
|
||||||
|
image: "daprio/daprd:latest"
|
||||||
|
container_name: connectServer_dapr
|
||||||
|
command: [ "./daprd", "-app-id", "connectServer", "-app-port", "8080",
|
||||||
|
"-components-path", "/components",
|
||||||
|
"-config", "/components/config.yaml",
|
||||||
|
"-placement-host-address", "dapr-placement:50006" ]
|
||||||
|
depends_on:
|
||||||
|
- connectServer
|
||||||
|
network_mode: "service:connectServer"
|
||||||
|
volumes:
|
||||||
|
- "./dapr-components/:/components"
|
||||||
|
|
||||||
|
loginServer:
|
||||||
|
image: munique/openmu-login
|
||||||
|
container_name: loginServer
|
||||||
|
ports:
|
||||||
|
- "50001"
|
||||||
|
- "9464" # Prometheus
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
depends_on:
|
||||||
|
- zipkin
|
||||||
|
- database
|
||||||
|
|
||||||
|
loginServer-dapr:
|
||||||
|
image: "daprio/daprd:latest"
|
||||||
|
container_name: loginServer_dapr
|
||||||
|
command: [ "./daprd", "-app-id", "loginServer", "-app-port", "8080",
|
||||||
|
"-components-path", "/components",
|
||||||
|
"-config", "/components/config.yaml",
|
||||||
|
"-placement-host-address", "dapr-placement:50006" ]
|
||||||
|
depends_on:
|
||||||
|
- loginServer
|
||||||
|
network_mode: "service:loginServer"
|
||||||
|
volumes:
|
||||||
|
- "./dapr-components/:/components"
|
||||||
|
|
||||||
|
friendServer:
|
||||||
|
image: munique/openmu-friend
|
||||||
|
container_name: friendServer
|
||||||
|
ports:
|
||||||
|
- "50001"
|
||||||
|
- "9464" # Prometheus
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
depends_on:
|
||||||
|
- chatServer-dapr
|
||||||
|
- database
|
||||||
|
- zipkin
|
||||||
|
|
||||||
|
friendServer-dapr:
|
||||||
|
image: "daprio/daprd:latest"
|
||||||
|
container_name: friendServer_dapr
|
||||||
|
command: [ "./daprd", "-app-id", "friendServer", "-app-port", "8080",
|
||||||
|
"-components-path", "/components",
|
||||||
|
"-config", "/components/config.yaml",
|
||||||
|
"-placement-host-address", "dapr-placement:50006" ]
|
||||||
|
depends_on:
|
||||||
|
- friendServer
|
||||||
|
network_mode: "service:friendServer"
|
||||||
|
volumes:
|
||||||
|
- "./dapr-components/:/components"
|
||||||
|
|
||||||
|
guildServer:
|
||||||
|
image: munique/openmu-guild
|
||||||
|
container_name: guildServer
|
||||||
|
ports:
|
||||||
|
- "50001"
|
||||||
|
- "9464" # Prometheus
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
- zipkin
|
||||||
|
|
||||||
|
guildServer-dapr:
|
||||||
|
image: "daprio/daprd:latest"
|
||||||
|
container_name: guildServer_dapr
|
||||||
|
command: [ "./daprd", "-app-id", "guildServer", "-app-port", "8080",
|
||||||
|
"-components-path", "/components",
|
||||||
|
"-config", "/components/config.yaml",
|
||||||
|
"-placement-host-address", "dapr-placement:50006" ]
|
||||||
|
depends_on:
|
||||||
|
- guildServer
|
||||||
|
network_mode: "service:guildServer"
|
||||||
|
volumes:
|
||||||
|
- "./dapr-components/:/components"
|
||||||
|
|
||||||
|
chatServer:
|
||||||
|
image: munique/openmu-chat
|
||||||
|
container_name: chatServer
|
||||||
|
environment:
|
||||||
|
APPID: chatServer
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
ports:
|
||||||
|
- "55980:55980"
|
||||||
|
- "50001"
|
||||||
|
- "9464" # Prometheus
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
- zipkin
|
||||||
|
|
||||||
|
chatServer-dapr:
|
||||||
|
image: "daprio/daprd:latest"
|
||||||
|
container_name: chatServer_dapr
|
||||||
|
command: [ "./daprd", "-app-id", "chatServer", "-app-port", "8080",
|
||||||
|
"-components-path", "/components",
|
||||||
|
"-config", "/components/config.yaml",
|
||||||
|
"-placement-host-address", "dapr-placement:50006" ]
|
||||||
|
depends_on:
|
||||||
|
- chatServer
|
||||||
|
network_mode: "service:chatServer"
|
||||||
|
volumes:
|
||||||
|
- "./dapr-components/:/components"
|
||||||
|
|
||||||
|
|
||||||
|
adminPanel:
|
||||||
|
image: munique/openmu-admin
|
||||||
|
container_name: adminPanel
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
ports:
|
||||||
|
- "8080"
|
||||||
|
- "9464" # Prometheus
|
||||||
|
environment:
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
PATH_BASE: /admin/
|
||||||
|
volumes:
|
||||||
|
- ./.htpasswd:/etc/nginx/.htpasswd
|
||||||
|
|
||||||
|
adminPanel-dapr:
|
||||||
|
image: "daprio/daprd:latest"
|
||||||
|
container_name: adminPanel_dapr
|
||||||
|
command: [ "./daprd", "-app-id", "adminPanel", "-app-port", "8080",
|
||||||
|
"-components-path", "/components",
|
||||||
|
"-config", "/components/config.yaml",
|
||||||
|
"-placement-host-address", "dapr-placement:50006" ]
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- adminPanel
|
||||||
|
network_mode: "service:adminPanel"
|
||||||
|
volumes:
|
||||||
|
- "./dapr-components/:/components"
|
||||||
|
|
||||||
|
gameServer0:
|
||||||
|
image: munique/openmu-game
|
||||||
|
container_name: gameServer0
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Dapr/GameServer.Host/Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8080"
|
||||||
|
- "50001"
|
||||||
|
- "55901:55901"
|
||||||
|
- "55902:55902"
|
||||||
|
- "9464" # Prometheus
|
||||||
|
environment:
|
||||||
|
GS_ID: 0
|
||||||
|
APPID: gameServer0
|
||||||
|
PATH_BASE: /gameServer/0/
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
depends_on:
|
||||||
|
- connectServer-dapr
|
||||||
|
- loginServer-dapr
|
||||||
|
- friendServer-dapr
|
||||||
|
- rabbit
|
||||||
|
- zipkin
|
||||||
|
- database
|
||||||
|
- loki
|
||||||
|
|
||||||
|
gameServer0-dapr:
|
||||||
|
image: "daprio/daprd:latest"
|
||||||
|
container_name: gameserver0_dapr
|
||||||
|
command: [ "./daprd", "-app-id", "gameServer0", "-app-port", "8080",
|
||||||
|
"-components-path", "/components",
|
||||||
|
"-config", "/components/config.yaml",
|
||||||
|
"-placement-host-address", "dapr-placement:50006" ]
|
||||||
|
depends_on:
|
||||||
|
- gameServer0
|
||||||
|
network_mode: "service:gameServer0"
|
||||||
|
volumes:
|
||||||
|
- "./dapr-components/:/components"
|
||||||
|
|
||||||
|
gameServer1:
|
||||||
|
image: munique/openmu-game
|
||||||
|
container_name: gameServer1
|
||||||
|
build:
|
||||||
|
context: ../../src
|
||||||
|
dockerfile: Dapr/GameServer.Host/Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8080"
|
||||||
|
- "50001"
|
||||||
|
- "55903:55903"
|
||||||
|
- "55904:55904"
|
||||||
|
- "9464" # Prometheus
|
||||||
|
environment:
|
||||||
|
GS_ID: 1
|
||||||
|
APPID: gameServer1
|
||||||
|
PATH_BASE: /gameServer/1/
|
||||||
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
depends_on:
|
||||||
|
- connectServer-dapr
|
||||||
|
- loginServer-dapr
|
||||||
|
- friendServer-dapr
|
||||||
|
- rabbit
|
||||||
|
- zipkin
|
||||||
|
- database
|
||||||
|
- loki
|
||||||
|
|
||||||
|
gameServer1-dapr:
|
||||||
|
image: "daprio/daprd:latest"
|
||||||
|
container_name: gameserver1_dapr
|
||||||
|
command: [ "./daprd", "-app-id", "gameServer1", "-app-port", "8080",
|
||||||
|
"-components-path", "/components",
|
||||||
|
"-config", "/components/config.yaml",
|
||||||
|
"-placement-host-address", "dapr-placement:50006" ]
|
||||||
|
depends_on:
|
||||||
|
- gameServer1
|
||||||
|
network_mode: "service:gameServer1"
|
||||||
|
volumes:
|
||||||
|
- "./dapr-components/:/components"
|
||||||
1157
deploy/distributed/grafana.ini
Normal file
1157
deploy/distributed/grafana.ini
Normal file
File diff suppressed because it is too large
Load Diff
10
deploy/distributed/grafana_datasources.yaml
Normal file
10
deploy/distributed/grafana_datasources.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: 1
|
||||||
|
datasources:
|
||||||
|
- name: Loki
|
||||||
|
type: loki
|
||||||
|
access: proxy
|
||||||
|
url: http://loki:3100
|
||||||
|
- name: Prometheus
|
||||||
|
type: prometheus
|
||||||
|
access: proxy
|
||||||
|
url: http://prometheus:9090
|
||||||
36
deploy/distributed/launchSettings.json
Normal file
36
deploy/distributed/launchSettings.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Docker Compose": {
|
||||||
|
"commandName": "DockerCompose",
|
||||||
|
"commandVersion": "1.0",
|
||||||
|
"serviceActions": {
|
||||||
|
"connectServer": "StartDebugging",
|
||||||
|
"connectServer-dapr": "StartWithoutDebugging",
|
||||||
|
"dapr-placement": "StartWithoutDebugging",
|
||||||
|
"database": "StartWithoutDebugging",
|
||||||
|
"gameServer1": "StartDebugging",
|
||||||
|
"gameServer1-dapr": "StartWithoutDebugging",
|
||||||
|
"rabbit": "StartWithoutDebugging",
|
||||||
|
"friendServer": "StartDebugging",
|
||||||
|
"friendServer-dapr": "StartWithoutDebugging",
|
||||||
|
"loginServer": "StartDebugging",
|
||||||
|
"loginServer-dapr": "StartWithoutDebugging",
|
||||||
|
"guildServer": "StartDebugging",
|
||||||
|
"guildServer-dapr": "StartWithoutDebugging",
|
||||||
|
"chatServer": "StartDebugging",
|
||||||
|
"chatServer-dapr": "StartWithoutDebugging",
|
||||||
|
"adminPanel": "StartDebugging",
|
||||||
|
"adminPanel-dapr": "StartWithoutDebugging",
|
||||||
|
"grafana": "StartWithoutDebugging",
|
||||||
|
"loki": "StartWithoutDebugging",
|
||||||
|
"minio": "StartWithoutDebugging",
|
||||||
|
"nginx-80": "StartWithoutDebugging",
|
||||||
|
"prometheus": "StartWithoutDebugging",
|
||||||
|
"zipkin": "StartWithoutDebugging",
|
||||||
|
"gameServer0": "StartWithoutDebugging",
|
||||||
|
"gameServer0-dapr": "StartWithoutDebugging",
|
||||||
|
"redis-state": "StartWithoutDebugging"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
deploy/distributed/loki-config.yaml
Normal file
36
deploy/distributed/loki-config.yaml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
auth_enabled: false
|
||||||
|
server:
|
||||||
|
http_listen_port: 3100
|
||||||
|
memberlist:
|
||||||
|
join_members:
|
||||||
|
- loki:7946
|
||||||
|
schema_config:
|
||||||
|
configs:
|
||||||
|
- from: 2021-08-01
|
||||||
|
store: boltdb-shipper
|
||||||
|
object_store: s3
|
||||||
|
schema: v11
|
||||||
|
index:
|
||||||
|
prefix: index_
|
||||||
|
period: 24h
|
||||||
|
#limits_config:
|
||||||
|
# max_streams_per_user: 100000
|
||||||
|
common:
|
||||||
|
path_prefix: /loki
|
||||||
|
replication_factor: 1
|
||||||
|
storage:
|
||||||
|
s3:
|
||||||
|
endpoint: minio:9000
|
||||||
|
insecure: true
|
||||||
|
bucketnames: loki-data
|
||||||
|
access_key_id: loki
|
||||||
|
secret_access_key: supersecret
|
||||||
|
s3forcepathstyle: true
|
||||||
|
ring:
|
||||||
|
kvstore:
|
||||||
|
store: memberlist
|
||||||
|
ruler:
|
||||||
|
storage:
|
||||||
|
s3:
|
||||||
|
bucketnames: loki-ruler
|
||||||
65
deploy/distributed/nginx.dev.conf
Normal file
65
deploy/distributed/nginx.dev.conf
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
events {
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
# this is required to proxy Grafana Live WebSocket connections.
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
auth_basic "Protected Site";
|
||||||
|
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
|
||||||
|
location /zipkin {
|
||||||
|
proxy_pass http://zipkin:9411/zipkin/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /grafana/ {
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_pass http://grafana:3000/;
|
||||||
|
|
||||||
|
# Auth by nginx
|
||||||
|
proxy_set_header X-WEBAUTH-USER $remote_user;
|
||||||
|
proxy_set_header Authorization "";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Proxy Grafana Live WebSocket connections.
|
||||||
|
location /grafana/api/live {
|
||||||
|
rewrite ^/grafana/(.*) /$1 break;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
|
||||||
|
proxy_pass http://grafana:3000/;
|
||||||
|
|
||||||
|
# Auth by nginx
|
||||||
|
proxy_set_header X-WEBAUTH-USER $remote_user;
|
||||||
|
proxy_set_header Authorization "";
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ (/admin)(.*) {
|
||||||
|
proxy_pass http://adminPanel:8080/admin$2;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Public API
|
||||||
|
location ~ (/serverInfo)(.*) {
|
||||||
|
proxy_pass http://connectServer:8080/serverInfo$2;
|
||||||
|
auth_basic off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Game Servers:
|
||||||
|
location ~ (/gameServer/(\d+)(.*)) {
|
||||||
|
proxy_pass http://gameServer$2:8080$1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
deploy/distributed/nginx.prod.certificates.conf.template
Normal file
2
deploy/distributed/nginx.prod.certificates.conf.template
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ssl_certificate /etc/nginx/ssl/live/$DOMAIN_NAME/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/live/$DOMAIN_NAME/privkey.pem;
|
||||||
70
deploy/distributed/nginx.prod443.conf
Normal file
70
deploy/distributed/nginx.prod443.conf
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
events {
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
# this is required to proxy Grafana Live WebSocket connections.
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 default_server ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
|
||||||
|
include conf.d/nginx.server_name.conf;
|
||||||
|
include conf.d/nginx.prod.certificates.conf;
|
||||||
|
|
||||||
|
auth_basic "Protected Site";
|
||||||
|
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
|
||||||
|
location /zipkin {
|
||||||
|
proxy_pass http://zipkin:9411/zipkin/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /grafana/ {
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_pass http://grafana:3000/;
|
||||||
|
|
||||||
|
# Auth by nginx
|
||||||
|
proxy_set_header X-WEBAUTH-USER $remote_user;
|
||||||
|
proxy_set_header Authorization "";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Proxy Grafana Live WebSocket connections.
|
||||||
|
location /grafana/api/live {
|
||||||
|
rewrite ^/grafana/(.*) /$1 break;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
|
||||||
|
proxy_pass http://grafana:3000/;
|
||||||
|
|
||||||
|
# Auth by nginx
|
||||||
|
proxy_set_header X-WEBAUTH-USER $remote_user;
|
||||||
|
proxy_set_header Authorization "";
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ (/admin)(.*) {
|
||||||
|
proxy_pass http://adminPanel:8080/admin$2;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Public API
|
||||||
|
location ~ (/serverInfo)(.*) {
|
||||||
|
proxy_pass http://connectServer:8080/serverInfo$2;
|
||||||
|
auth_basic off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Game Servers:
|
||||||
|
location ~ (/gameServer/(\d+)(.*)) {
|
||||||
|
proxy_pass http://gameServer$2:8080$1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
deploy/distributed/nginx.prod80.conf
Normal file
20
deploy/distributed/nginx.prod80.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
events {
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
include conf.d/nginx.server_name.conf;
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
deploy/distributed/nginx.server_name.conf.template
Normal file
1
deploy/distributed/nginx.server_name.conf.template
Normal file
@@ -0,0 +1 @@
|
|||||||
|
server_name $DOMAIN_NAME;
|
||||||
14
deploy/distributed/prometheus.yml
Normal file
14
deploy/distributed/prometheus.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
global:
|
||||||
|
scrape_interval: 10s
|
||||||
|
evaluation_interval: 10s
|
||||||
|
|
||||||
|
rule_files:
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: prometheus
|
||||||
|
static_configs:
|
||||||
|
- targets: ['localhost:9090']
|
||||||
|
- job_name: openmu
|
||||||
|
static_configs:
|
||||||
|
- targets: ['gameServer1:9464', 'connectServer:9464', 'chatServer:9464']
|
||||||
|
|
||||||
13
dev.sh
Normal file
13
dev.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
function generate_certificates {
|
||||||
|
docker run --rm --entrypoint "" \
|
||||||
|
-v $PWD/certificates:/certificates \
|
||||||
|
mcr.microsoft.com/dotnet/sdk:5.0 \
|
||||||
|
sh -c "dotnet dev-certs https --clean && dotnet dev-certs https -ep /certificates/aspnetapp.pfx -p ${1}"
|
||||||
|
|
||||||
|
if [ $? == 0 ]; then
|
||||||
|
export CERTIFICATE_PASSWORD=${1}
|
||||||
|
echo "success"
|
||||||
|
fi
|
||||||
|
}
|
||||||
53
docs/GameMap.md
Normal file
53
docs/GameMap.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# GameMap
|
||||||
|
|
||||||
|
I want to give a quick description about how the [game map](../src/GameLogic/GameMap.cs),
|
||||||
|
especially observing between players/npc works.
|
||||||
|
|
||||||
|
## AreaOfInterestManager
|
||||||
|
|
||||||
|
Each game map has an area of interest manager. It takes care of the event
|
||||||
|
subscriptions between objects, in case they were added, moved or removed at the
|
||||||
|
map.
|
||||||
|
|
||||||
|
The default implementation ([BucketAreaOfInterestManager](../src/GameLogic/BucketAreaOfInterestManager.cs))
|
||||||
|
creates a BucketMap, which is described below.
|
||||||
|
Other (simpler) implementations may be possible for the future for maps which
|
||||||
|
are more likely to be "empty" or require that all objects of a map need to know
|
||||||
|
all other objects (e.g. Duel map).
|
||||||
|
|
||||||
|
## BucketMap
|
||||||
|
|
||||||
|
The [bucket map](../src/GameLogic/BucketMap{T}.cs) is basically a two-dimensional
|
||||||
|
data structure.
|
||||||
|
We split the map of 256 x 256 possible coordinates into "[buckets](../src/GameLogic/Bucket{T}.cs)".
|
||||||
|
For example, each bucket covers 8 x 8 coordinates.
|
||||||
|
|
||||||
|
A player (or other "observers") can observe buckets, so that it gets informed
|
||||||
|
when objects (other players, npc, dropped items) enter or leave this bucket.
|
||||||
|
When a player moves and comes into the range of a bucket (defined by an
|
||||||
|
"info range"), it subscribes this enter/leave events and adds all existing
|
||||||
|
objects of this bucket to his view.
|
||||||
|
|
||||||
|
You may ask, why I introduced such a structure and not simply use a list of
|
||||||
|
objects and compare the distance to them when moving to decide if a object
|
||||||
|
should be sent (add/remove) to the game client.
|
||||||
|
As far as I know, the original server works like that and has a lot of lag when
|
||||||
|
a lot of players (more than thousand at castle siege) are on the same map, all
|
||||||
|
moving around.
|
||||||
|
This is a O(n²) problem where n is the number of objects on the same map - this
|
||||||
|
can get pretty complex very fast.
|
||||||
|
|
||||||
|
Now with my concept, this search is only happening when a player enters a new
|
||||||
|
bucket - and then it searches only for new buckets in range, not for other
|
||||||
|
individual objects.
|
||||||
|
So this is not as complex when you have many objects on your map. Of course,
|
||||||
|
this needs a bit more memory and is slower on empty maps, but IMHO that's
|
||||||
|
really worth it - usually, game maps are packed with monsters, players and a
|
||||||
|
lot of dropped items.
|
||||||
|
|
||||||
|
## Other ideas
|
||||||
|
|
||||||
|
Instead of partitioning a map into buckets (where a lot of them are empty), we
|
||||||
|
could try to use some other 2d index structures, like
|
||||||
|
[R-trees](https://en.wikipedia.org/wiki/R-tree) or [B-Trees](https://en.wikipedia.org/wiki/B-tree)
|
||||||
|
with [Z-Ordering](https://en.wikipedia.org/wiki/Z-order_curve).
|
||||||
116
docs/MasterSystem.md
Normal file
116
docs/MasterSystem.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# Master System
|
||||||
|
|
||||||
|
## What is it?
|
||||||
|
|
||||||
|
When a character reached a certain level (usually level 400) and completes a quest,
|
||||||
|
its character class changes to a *master character class*.
|
||||||
|
This unlocks the *Master Skill Tree* which allows to distribute points to master
|
||||||
|
skills.
|
||||||
|
Points are given by each master level the player reaches (just like before, by
|
||||||
|
gaining experience).
|
||||||
|
|
||||||
|
## Types of master skills
|
||||||
|
|
||||||
|
Basically, there are two types of master skills in a skill tree:
|
||||||
|
|
||||||
|
### Passive skills
|
||||||
|
|
||||||
|
When these skills are learned, they give certain power-ups passively. For example,
|
||||||
|
there are master skills to increase the maximum health or to increase the
|
||||||
|
attack damage.
|
||||||
|
|
||||||
|
### Active skills
|
||||||
|
|
||||||
|
When learned, these skills appear in the skill list. Most skills of this type replace
|
||||||
|
previously existing skills. The replaced skills are staying in the background,
|
||||||
|
are not visible in the game client, but their internal value still apply to the
|
||||||
|
master skill as well.
|
||||||
|
The master skill just defines how much damage or buff power is added to the
|
||||||
|
replaced skill.
|
||||||
|
|
||||||
|
## Structure of the master skill tree
|
||||||
|
|
||||||
|
The master skill tree consists of three roots.
|
||||||
|
The skills are put into rows which defines the *rank* of a skill.
|
||||||
|
By default, there 5 ranks available. However, the game client would support up
|
||||||
|
to 9 ranks. Each skill usually can have up to 20 levels, some only have 10. The
|
||||||
|
client probably supports more than that.
|
||||||
|
|
||||||
|
A skill can be defined to depend on a skill of the same or the previous rank of
|
||||||
|
the same root.
|
||||||
|
|
||||||
|
Each character class is able to learn different skills, which are sometimes
|
||||||
|
exclusive to the character class. So, one skill can be available for multiple
|
||||||
|
character classes.
|
||||||
|
The root and rank for a skill is always the same for all character classes.
|
||||||
|
The visual appearance on the client may differ (more on that later).
|
||||||
|
|
||||||
|
## Requisitions of learning a skill
|
||||||
|
|
||||||
|
To learn a skill, the following checks are done by the server (and client).
|
||||||
|
|
||||||
|
### Character class
|
||||||
|
|
||||||
|
The skill must be defined for the class of the character.
|
||||||
|
|
||||||
|
### Rank
|
||||||
|
|
||||||
|
The skill must either be in the first rank, or a skill in the previous rank of
|
||||||
|
the same root must at least of level 10.
|
||||||
|
|
||||||
|
### Required Skill
|
||||||
|
|
||||||
|
If the skill has required skills defined (it's optional), these skills must be
|
||||||
|
at least of level 10.
|
||||||
|
|
||||||
|
## Client implementation
|
||||||
|
|
||||||
|
Some short notes about the client:
|
||||||
|
|
||||||
|
* There is a message for the master level etc. (F3 50)
|
||||||
|
|
||||||
|
* It contains health and mana, too. If this packet isn't sent, a master
|
||||||
|
character appears without health/mana.
|
||||||
|
|
||||||
|
* There is a message for the learned master skills (F3 53)
|
||||||
|
|
||||||
|
* The information about each skill contains:
|
||||||
|
|
||||||
|
* Skill Number
|
||||||
|
|
||||||
|
* Skill Index
|
||||||
|
|
||||||
|
* Defines were the skill is located in the clients interface
|
||||||
|
|
||||||
|
* I wonder why they need this in the message, since the client already
|
||||||
|
knows the index of a skill itself
|
||||||
|
|
||||||
|
* May differ between character classes
|
||||||
|
|
||||||
|
* Current Level
|
||||||
|
|
||||||
|
* Value of its effect at the current level
|
||||||
|
|
||||||
|
* Value of its effect at the next level
|
||||||
|
|
||||||
|
* Even if no skill was learned, this message needs to be sent - otherwise it
|
||||||
|
may still contain the master information about the previously played master
|
||||||
|
character.
|
||||||
|
|
||||||
|
## Server implementation
|
||||||
|
|
||||||
|
### Adding Points
|
||||||
|
|
||||||
|
* For code, see [AddMasterPointAction](https://github.com/MUnique/OpenMU/tree/master/src/GameLogic/PlayerActions/Character/AddMasterPointAction.cs).
|
||||||
|
* Request Packet: [C1F352 - Add Master Skill Point](Packets/C1-F3-52-AddMasterSkillPoint_by-client.md)
|
||||||
|
* Response Packet: [C1F352 - Master skill level update](Packets/C1-F3-52-MasterSkillLevelUpdate_by-server.md)
|
||||||
|
|
||||||
|
### Sending Master Stats (F3 50)
|
||||||
|
|
||||||
|
* For code, see [UpdateMasterStatsPlugIn](https://github.com/MUnique/OpenMU/tree/master/src/GameServer/RemoteView/Character/UpdateMasterStatsPlugIn.cs).
|
||||||
|
* Request Packet: [C2F350 - Master Stats Update](Packets/C1-F3-50-MasterStatsUpdate_by-server.md)
|
||||||
|
|
||||||
|
### Sending Master Skills (F3 53)
|
||||||
|
|
||||||
|
* For code, see [UpdateMasterSkillsPlugIn](https://github.com/MUnique/OpenMU/tree/master/src/GameServer/RemoteView/Character/UpdateMasterSkillsPlugIn.cs).
|
||||||
|
* Packet: [C2F353 - Master Skill List](Packets/C2-F3-53-MasterSkillList_by-server.md)
|
||||||
87
docs/PacketStructureTests.md
Normal file
87
docs/PacketStructureTests.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Packet Structure Tests Implementation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This implementation provides automatically generated tests for packet structures defined in XML files. The tests validate that packet definitions are correct and would catch issues like incorrect packet lengths (as mentioned in PR #622).
|
||||||
|
|
||||||
|
## Files Created
|
||||||
|
|
||||||
|
### 1. `src/Network/Packets/GenerateTests.xslt`
|
||||||
|
XSLT transformation that generates C# test code from XML packet definitions. Features:
|
||||||
|
- Validates fixed-length packets/structures against their declared lengths
|
||||||
|
- Tests variable-length packets' GetRequiredSize methods
|
||||||
|
- Validates field boundaries to prevent buffer overruns
|
||||||
|
- Generates syntactically correct C# test code with proper naming
|
||||||
|
|
||||||
|
### 2. `tests/MUnique.OpenMU.Network.Packets.Tests/`
|
||||||
|
New test project that:
|
||||||
|
- Automatically generates test files during build (when `ci` is not set)
|
||||||
|
- Integrates with existing test infrastructure (NUnit, StyleCop, etc.)
|
||||||
|
- Added to main solution file for CI/CD integration
|
||||||
|
|
||||||
|
### 3. Test Files Generated
|
||||||
|
- `ClientToServerPacketTests.cs` - Tests for client-to-server packets
|
||||||
|
- `ServerToClientPacketTests.cs` - Tests for server-to-client packets
|
||||||
|
- `ChatServerPacketTests.cs` - Tests for chat server packets
|
||||||
|
- `ConnectServerPacketTests.cs` - Tests for connect server packets
|
||||||
|
|
||||||
|
## Types of Validation
|
||||||
|
|
||||||
|
### Fixed-Length Validation
|
||||||
|
```csharp
|
||||||
|
// Validates declared length matches calculated size
|
||||||
|
const int expectedLength = 20; // From XML
|
||||||
|
const int actualLength = PlayerShopItem.Length; // From generated struct
|
||||||
|
Assert.That(actualLength, Is.EqualTo(expectedLength));
|
||||||
|
|
||||||
|
// Validates field boundaries
|
||||||
|
Assert.That(fieldIndex + fieldSize, Is.LessThanOrEqualTo(expectedLength));
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variable-Length Validation
|
||||||
|
```csharp
|
||||||
|
// Tests GetRequiredSize method accuracy
|
||||||
|
const string testString = "TestData";
|
||||||
|
var calculatedSize = StoredItem.GetRequiredSize(testString);
|
||||||
|
var expectedSize = Encoding.UTF8.GetByteCount(testString) + 1 + baseOffset;
|
||||||
|
Assert.That(calculatedSize, Is.EqualTo(expectedSize));
|
||||||
|
```
|
||||||
|
|
||||||
|
### Field Boundary Validation
|
||||||
|
```csharp
|
||||||
|
// Ensures fields don't exceed packet boundaries
|
||||||
|
Assert.That(fieldIndex + fieldSize, Is.LessThanOrEqualTo(packetLength));
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **Build Process**: During build, XSLT transformations read XML packet definitions
|
||||||
|
2. **Code Generation**: Generates comprehensive test methods for each packet/structure
|
||||||
|
3. **Validation**: Tests run during normal test execution, catching definition errors
|
||||||
|
4. **Integration**: Fully integrated with existing CI/CD pipeline
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
- **Automatic Detection**: Catches packet definition errors at build time
|
||||||
|
- **Comprehensive Coverage**: Tests all packet types and structures
|
||||||
|
- **Zero Maintenance**: Tests are automatically updated when XML definitions change
|
||||||
|
- **Early Error Detection**: Prevents runtime issues from malformed packets
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The tests run automatically as part of the normal build and test process. No manual intervention required.
|
||||||
|
|
||||||
|
To run tests manually:
|
||||||
|
```bash
|
||||||
|
dotnet test tests/MUnique.OpenMU.Network.Packets.Tests/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Issues Caught
|
||||||
|
|
||||||
|
The generated tests would catch issues like:
|
||||||
|
- Packet length declared as 10 but fields require 12 bytes
|
||||||
|
- Field starting at index 8 with size 4 in a 10-byte packet
|
||||||
|
- Incorrect GetRequiredSize calculations
|
||||||
|
- Overlapping field definitions
|
||||||
|
|
||||||
|
This addresses the core issue mentioned in PR #622 where packet structures were defined incorrectly.
|
||||||
154
docs/Packets/Appearance.md
Normal file
154
docs/Packets/Appearance.md
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
# Appearance
|
||||||
|
|
||||||
|
The appearance of characters is serialized as follows.
|
||||||
|
Webzen did a "good" job saving one bit here and there, so it's a bit complicated
|
||||||
|
sometimes (e.g. wings and pets).
|
||||||
|
It seems like the structure is historically grown.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
Please read this table like a stream of bits. E.g. if there are 8 bits of 1 byte
|
||||||
|
are specified in a row, the highest bits come first.
|
||||||
|
|
||||||
|
| Byte index | Length | Data type | Description |
|
||||||
|
|----------|---------|-------------|------------|
|
||||||
|
| 0 | 4 | bit | Character class |
|
||||||
|
| 0 | 4 | bit | Character pose, see below |
|
||||||
|
| 1 | 1 | byte | Left hand item index. 0xFF if empty. |
|
||||||
|
| 2 | 1 | byte | Right hand item index. 0xFF if empty. |
|
||||||
|
| 3 | 4 | bit | Helm item index (lower 4 bits). See byte index 9 and 13 for the rest. |
|
||||||
|
| 3 | 4 | bit | Armor item index (lower 4 bits). See byte index 9 and 14 for the rest. |
|
||||||
|
| 4 | 4 | bit | Pants item index (lower 4 bits). See byte index 9 and 14 for the rest. |
|
||||||
|
| 4 | 4 | bit | Gloves item index (lower 4 bits). See byte index 9 and 15 for the rest. |
|
||||||
|
| 5 | 4 | bit | Boots item index (lower 4 bits). See byte index 9 and 15 for the rest. |
|
||||||
|
| 5 | 4 | bit | Pets and wings flags, see below |
|
||||||
|
| 6 | 3 | bit | Left hand item level |
|
||||||
|
| 6 | 3 | bit | Right hand item level |
|
||||||
|
| 6~7 | 3 | bit | Helm item level |
|
||||||
|
| 7 | 3 | bit | Armor item level |
|
||||||
|
| 7 | 3 | bit | Pants item level |
|
||||||
|
| 7~8 | 3 | bit | Gloves item level |
|
||||||
|
| 8 | 3 | bit | Boots item level |
|
||||||
|
| 8 | 3 | bit | unused |
|
||||||
|
| 9 | 1 | bit | Helm item index (5th bit) |
|
||||||
|
| 9 | 1 | bit | Armor item index (5th bit) |
|
||||||
|
| 9 | 1 | bit | Pants item index (5th bit) |
|
||||||
|
| 9 | 1 | bit | Gloves item index (5th bit) |
|
||||||
|
| 9 | 1 | bit | Boots item index (5th bit) |
|
||||||
|
| 9 | 3 | bit | Wing item index (see table below) |
|
||||||
|
| 10 | 1 | bit | Helm excellent option flag |
|
||||||
|
| 10 | 1 | bit | Armor excellent option flag |
|
||||||
|
| 10 | 1 | bit | Pants excellent option flag |
|
||||||
|
| 10 | 1 | bit | Gloves excellent option flag |
|
||||||
|
| 10 | 1 | bit | Boots excellent option flag |
|
||||||
|
| 10 | 1 | bit | Left hand item excellent option flag |
|
||||||
|
| 10 | 1 | bit | Right hand item excellent option flag |
|
||||||
|
| 10 | 1 | bit | Dinorant flag |
|
||||||
|
| 11 | 1 | bit | Helm ancient option flag |
|
||||||
|
| 11 | 1 | bit | Armor ancient option flag |
|
||||||
|
| 11 | 1 | bit | Pants ancient option flag |
|
||||||
|
| 11 | 1 | bit | Gloves ancient option flag |
|
||||||
|
| 11 | 1 | bit | Boots ancient option flag |
|
||||||
|
| 11 | 1 | bit | Left hand item ancient option flag |
|
||||||
|
| 11 | 1 | bit | Right hand item ancient option flag |
|
||||||
|
| 11 | 1 | bit | Full ancient set flag |
|
||||||
|
| 12 | 3 | bit | Left hand item group. 111 = empty |
|
||||||
|
| 12 | 1 | bit | unused or empty flag? |
|
||||||
|
| 12 | 1 | bit | unused |
|
||||||
|
| 12 | 1 | bit | Fenrir flag |
|
||||||
|
| 12 | 1 | bit | unused |
|
||||||
|
| 12 | 1 | bit | Dark horse flag |
|
||||||
|
| 13 | 3 | bit | Right hand item group. 111 = empty |
|
||||||
|
| 13 | 1 | bit | unused or empty flag? |
|
||||||
|
| 13 | 4 | bit | Helm item index (6-9th bit). 0xF = empty |
|
||||||
|
| 14 | 4 | bit | Armor item index (6-9th bit). 0xF = empty |
|
||||||
|
| 14 | 4 | bit | Pants item index (6-9th bit). 0xF = empty |
|
||||||
|
| 15 | 4 | bit | Gloves item index (6-9th bit). 0xF = empty |
|
||||||
|
| 15 | 4 | bit | Boots item index (6-9th bit). 0xF = empty |
|
||||||
|
| 16 | 6 | bit | Pet item index, see below |
|
||||||
|
| 16 | 1 | bit | Blue fenrir flag |
|
||||||
|
| 16 | 1 | bit | Black fenrir flag |
|
||||||
|
| 17 | 4 | bit | Small Wing item index, see below |
|
||||||
|
| 17 | 3 | bit | unused |
|
||||||
|
| 17 | 1 | bit | Gold fenrir flag |
|
||||||
|
|
||||||
|
### Character pose
|
||||||
|
|
||||||
|
| Value | Meaning |
|
||||||
|
|-------|---------|
|
||||||
|
| 0 | Standing (default) |
|
||||||
|
| 1 | unused |
|
||||||
|
| 2 | Sitting (e.g. on a trunk) |
|
||||||
|
| 3 | Leaning (e.g. against a wall) |
|
||||||
|
| 4 | Hanging (at these strange things in Noria) |
|
||||||
|
|
||||||
|
Note: At Season 10 and above, the values are different.
|
||||||
|
Sitting is at 1, Leaning 2, Hanging 3. So, they removed the unused value.
|
||||||
|
|
||||||
|
### Item level calculation
|
||||||
|
|
||||||
|
The item levels are calculated with the following formula: ([Item Level] - 1) / 2.
|
||||||
|
|
||||||
|
This works until item level of 15, because it fits into 4 bits.
|
||||||
|
|
||||||
|
### Item indexes
|
||||||
|
|
||||||
|
The bytes are represented in binary format. X means the bit is used by something
|
||||||
|
else (see table above).
|
||||||
|
|
||||||
|
#### Pet items
|
||||||
|
|
||||||
|
| Item | 5th byte | 10th byte | 12th byte |
|
||||||
|
|-----------------------|----------|-----------|-----------|
|
||||||
|
| Guardian Angel | xxxxxx00 |
|
||||||
|
| Imp | xxxxxx01 |
|
||||||
|
| Unicorn | xxxxxx10 |
|
||||||
|
| Dinorant | xxxxxx11 | xxxxxxx1 ||
|
||||||
|
| Fenrir | xxxxxx11 | | xxxxxx1x |
|
||||||
|
| None | xxxxxx11 | xxxxxxx0 |
|
||||||
|
|
||||||
|
And some other pets:
|
||||||
|
|
||||||
|
| Item | 16th byte |
|
||||||
|
|-----------------------|-----------|
|
||||||
|
| Pet Panda | 111000xx |
|
||||||
|
| Pet Unicorn | 101000xx |
|
||||||
|
| Skeleton | 011000xx |
|
||||||
|
| Rudolph | 100000xx |
|
||||||
|
| Spirit of Guardian | 010000xx |
|
||||||
|
| Demon | 001000xx |
|
||||||
|
|
||||||
|
#### Wings
|
||||||
|
|
||||||
|
| Item | Character Class | 5th byte | 9th byte |
|
||||||
|
|-----------------------|-----------------|----------|----------|
|
||||||
|
| Wings of Elf | Fairy Elf | xxxx01xx | xxxxx001 |
|
||||||
|
| Wings of Heaven | Dark Wizard | xxxx01xx | xxxxx010 |
|
||||||
|
| Wings of Satan | Dark Knight | xxxx01xx | xxxxx011 |
|
||||||
|
| Wings of Mistery | Summoner | xxxx01xx | xxxxx100 |
|
||||||
|
| Wings of Spirit | Muse Elf | xxxx10xx | xxxxx001 |
|
||||||
|
| Wings of Soul | Soul Master | xxxx10xx | xxxxx010 |
|
||||||
|
| Wings of Dragon | Blade Knight | xxxx10xx | xxxxx011 |
|
||||||
|
| Wings of Darkness | Magic Gladiator | xxxx10xx | xxxxx100 |
|
||||||
|
| Cape of Lord | Dark Lord | xxxx10xx | xxxxx101 |
|
||||||
|
| Wings of Despair | Bloody Summoner | xxxx10xx | xxxxx110 |
|
||||||
|
| Cape of Fighter | Rage Fighter | xxxx10xx | xxxxx111 |
|
||||||
|
| Wing of Storm | Blade Master | xxxx11xx | xxxxx001 |
|
||||||
|
| Wing of Eternal | Grand Master | xxxx11xx | xxxxx010 |
|
||||||
|
| Wing of Illusion | High Elf | xxxx11xx | xxxxx011 |
|
||||||
|
| Wing of Ruin | Duel Master | xxxx11xx | xxxxx100 |
|
||||||
|
| Cape of Emperor | Lord Emperor | xxxx11xx | xxxxx101 |
|
||||||
|
| Wing of Dimension | Dimension Master| xxxx11xx | xxxxx110 |
|
||||||
|
| Cape of Overrule | Fist Master | xxxx11xx | xxxxx111 |
|
||||||
|
| None | | xxxx00xx | xxxxx000 |
|
||||||
|
|
||||||
|
#### Small Wings
|
||||||
|
|
||||||
|
| Wing Item | 5th byte | 17th byte |
|
||||||
|
|-----------------------|----------|-------|
|
||||||
|
| Small Cape of Lord | xxxx11xx | 0x20 |
|
||||||
|
| Small Wings of Mistery| xxxx11xx | 0x40 |
|
||||||
|
| Small Wings of Elf | xxxx11xx | 0x60 |
|
||||||
|
| Small Wings of Heaven | xxxx11xx | 0x80 |
|
||||||
|
| Small Wings of Satan | xxxx11xx | 0xA0 |
|
||||||
|
| Small Cloak of Warrior| xxxx11xx | 0xC0 |
|
||||||
18
docs/Packets/C1-00-01-Hello_by-server.md
Normal file
18
docs/Packets/C1-00-01-Hello_by-server.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# C1 00 01 - Hello (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the server after the client connected to the server.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
A game client will request the server list. The launcher would request the patch state.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 4 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x00 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | 0x01 | Packet header - sub packet type identifier |
|
||||||
19
docs/Packets/C1-00-Authenticate_by-client.md
Normal file
19
docs/Packets/C1-00-Authenticate_by-client.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 00 - Authenticate (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the client after it connected to the server, to authenticate itself.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The server will check the token. If it's correct, the client gets added to the requested chat room.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 16 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x00 | Packet header - packet type identifier |
|
||||||
|
| 4 | 2 | ShortLittleEndian | | RoomId |
|
||||||
|
| 6 | 10 | Binary | | Token; A token (integer number), formatted as string and "encrypted" with the 3-byte XOR key (FC CF AB). |
|
||||||
29
docs/Packets/C1-00-ChatMessage_by-server.md
Normal file
29
docs/Packets/C1-00-ChatMessage_by-server.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# C1 00 - ChatMessage (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player sends a chat message.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The message is shown in the chat box and above the character of the sender.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x00 | Packet header - packet type identifier |
|
||||||
|
| 2 | 1 | ChatMessageType | | Type |
|
||||||
|
| 3 | 10 | String | | Sender |
|
||||||
|
| 13 | | String | | Message |
|
||||||
|
|
||||||
|
### ChatMessageType Enum
|
||||||
|
|
||||||
|
Defines the type of a chat message.
|
||||||
|
|
||||||
|
| Value | Name | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| 0 | Normal | The message is a normal chat message, e.g. public, within a party or guild. |
|
||||||
|
| 2 | Whisper | The message is sent privately to the receiving player. |
|
||||||
19
docs/Packets/C1-00-PublicChatMessage_by-client.md
Normal file
19
docs/Packets/C1-00-PublicChatMessage_by-client.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 00 - PublicChatMessage (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player sends a public chat message.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The message is forwarded to all surrounding players, including the sender.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x00 | Packet header - packet type identifier |
|
||||||
|
| 3 | 10 | String | | Character |
|
||||||
|
| 13 | | String | | Message |
|
||||||
20
docs/Packets/C1-01-00-ChatRoomClientJoined_by-server.md
Normal file
20
docs/Packets/C1-01-00-ChatRoomClientJoined_by-server.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# C1 01 00 - ChatRoomClientJoined (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the server after another chat client joined the chat room.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The client will add the client in its list (if over 2 clients are connected to the same room), or show its name in the title bar.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 15 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x01 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | 0x00 | Packet header - sub packet type identifier |
|
||||||
|
| 4 | 1 | Byte | | ClientIndex |
|
||||||
|
| 5 | 10 | String | | Name |
|
||||||
20
docs/Packets/C1-01-01-ChatRoomClientLeft_by-server.md
Normal file
20
docs/Packets/C1-01-01-ChatRoomClientLeft_by-server.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# C1 01 01 - ChatRoomClientLeft (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the server after a chat client left the chat room.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The client will remove the client from its list, or mark its name in the title bar as offline.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 15 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x01 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | 0x01 | Packet header - sub packet type identifier |
|
||||||
|
| 4 | 1 | Byte | | ClientIndex |
|
||||||
|
| 5 | 10 | String | | Name |
|
||||||
17
docs/Packets/C1-01-LeaveChatRoom_by-client.md
Normal file
17
docs/Packets/C1-01-LeaveChatRoom_by-client.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# C1 01 - LeaveChatRoom (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the client when it leaves the chat room, before the connection closes.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The server will remove the client from the chat room, notifying the remaining clients.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 3 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x01 | Packet header - packet type identifier |
|
||||||
19
docs/Packets/C1-01-ObjectMessage_by-server.md
Normal file
19
docs/Packets/C1-01-ObjectMessage_by-server.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 01 - ObjectMessage (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
The server wants to show a message above any kind of character, even NPCs.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The message is shown above the character.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x01 | Packet header - packet type identifier |
|
||||||
|
| 3 | 2 | ShortBigEndian | | ObjectId |
|
||||||
|
| 5 | | String | | Message |
|
||||||
20
docs/Packets/C1-02-PatchCheckRequest_by-client.md
Normal file
20
docs/Packets/C1-02-PatchCheckRequest_by-client.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# C1 02 - PatchCheckRequest (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the client (launcher) to check if the patch version is high enough to be able to connect to the server.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The connect server will check the version and sends a 'PatchVersionOkay' or a 'ClientNeedsPatch' message.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 6 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x02 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | MajorVersion |
|
||||||
|
| 4 | 1 | Byte | | MinorVersion |
|
||||||
|
| 5 | 1 | Byte | | PatchVersion |
|
||||||
17
docs/Packets/C1-02-PatchVersionOkay_by-server.md
Normal file
17
docs/Packets/C1-02-PatchVersionOkay_by-server.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# C1 02 - PatchVersionOkay (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the server after the client (launcher) requested the to check the patch version and it was high enough.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The launcher will activate its start button.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 4 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x02 | Packet header - packet type identifier |
|
||||||
19
docs/Packets/C1-02-WhisperMessage_by-client.md
Normal file
19
docs/Packets/C1-02-WhisperMessage_by-client.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 02 - WhisperMessage (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player sends a private chat message to a specific target player.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The message is forwarded to the target player.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x02 | Packet header - packet type identifier |
|
||||||
|
| 3 | 10 | String | | ReceiverName |
|
||||||
|
| 13 | | String | | Message |
|
||||||
20
docs/Packets/C1-04-ChatMessage.md
Normal file
20
docs/Packets/C1-04-ChatMessage.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# C1 04 - ChatMessage
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the server after another chat client sent a message to the current chat room.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The client will show the message.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x04 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | SenderIndex |
|
||||||
|
| 4 | 1 | Byte | | MessageLength |
|
||||||
|
| 5 | | Binary | | Message; The message. It's "encrypted" with the 3-byte XOR key (FC CF AB). |
|
||||||
20
docs/Packets/C1-05-1-ClientNeedsPatch_by-server.md
Normal file
20
docs/Packets/C1-05-1-ClientNeedsPatch_by-server.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# C1 05 1 - ClientNeedsPatch (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the server after the client (launcher) requested to check the patch version and it requires an update.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The launcher will download the required patches and then activate the start button.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 138 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x05 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | 0x1 | Packet header - sub packet type identifier |
|
||||||
|
| 4 | 1 | Byte | | PatchVersion |
|
||||||
|
| 6 | | String | | PatchAddress; The patch address, usually to a ftp server. The address is usually "encrypted" with the 3-byte XOR key (FC CF AB). |
|
||||||
17
docs/Packets/C1-05-KeepAlive_by-client.md
Normal file
17
docs/Packets/C1-05-KeepAlive_by-client.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# C1 05 - KeepAlive (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
This packet is sent by the client in a fixed interval.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The server will keep the connection and chat room intact as long as the clients sends a message in a certain period of time.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 3 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x05 | Packet header - packet type identifier |
|
||||||
20
docs/Packets/C1-07-MagicEffectStatus_by-server.md
Normal file
20
docs/Packets/C1-07-MagicEffectStatus_by-server.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# C1 07 - MagicEffectStatus (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A magic effect was added or removed to the own or another player.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The user interface updates itself. If it's the effect of the own player, it's shown as icon at the top of the interface.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 7 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x07 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Boolean | | IsActive |
|
||||||
|
| 4 | 2 | ShortBigEndian | | PlayerId |
|
||||||
|
| 6 | 1 | Byte | | EffectId |
|
||||||
28
docs/Packets/C1-0B-MapEventState_by-server.md
Normal file
28
docs/Packets/C1-0B-MapEventState_by-server.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# C1 0B - MapEventState (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
The state of event is about to change.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The event's effect is shown.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 5 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x0B | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Boolean | | Enable |
|
||||||
|
| 4 | 1 | Events | | Event |
|
||||||
|
|
||||||
|
### Events Enum
|
||||||
|
|
||||||
|
Defines all events.
|
||||||
|
|
||||||
|
| Value | Name | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| 1 | RedDragon | Red dragon invasion. |
|
||||||
|
| 3 | GoldenDragon | Golden dragon invasion. |
|
||||||
29
docs/Packets/C1-0D-ServerMessage_by-server.md
Normal file
29
docs/Packets/C1-0D-ServerMessage_by-server.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# C1 0D - ServerMessage (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x0D | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | MessageType | | Type |
|
||||||
|
| 4 | | String | | Message |
|
||||||
|
|
||||||
|
### MessageType Enum
|
||||||
|
|
||||||
|
Defines a type of a server message.
|
||||||
|
|
||||||
|
| Value | Name | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| 0 | GoldenCenter | The message is shown as centered golden message in the client. |
|
||||||
|
| 1 | BlueNormal | The message is shown as a blue system message. |
|
||||||
|
| 2 | GuildNotice | The message is a guild notice, centered in green. |
|
||||||
19
docs/Packets/C1-0F-WeatherStatusUpdate_by-server.md
Normal file
19
docs/Packets/C1-0F-WeatherStatusUpdate_by-server.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 0F - WeatherStatusUpdate (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
The weather on the current map has been changed or the player entered the map.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The game client updates the weather effects.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 4 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x0F | Packet header - packet type identifier |
|
||||||
|
| 3 | 4 bit | Byte | | Weather; A random value between 0 and 2 (inclusive). |
|
||||||
|
| 3 | 4 bit | Byte | | Variation; A random value between 0 and 9 (inclusive). |
|
||||||
21
docs/Packets/C1-10-ObjectWalked075_by-server.md
Normal file
21
docs/Packets/C1-10-ObjectWalked075_by-server.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# C1 10 - ObjectWalked075 (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
An object in the observed scope (including the own player) walked to another position.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The object is animated to walk to the new position.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 8 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x10 | Packet header - packet type identifier |
|
||||||
|
| 3 | 2 | ShortBigEndian | | ObjectId |
|
||||||
|
| 5 | 1 | Byte | | TargetX |
|
||||||
|
| 6 | 1 | Byte | | TargetY |
|
||||||
|
| 7 | 4 bit | Byte | | TargetRotation |
|
||||||
22
docs/Packets/C1-10-WalkRequest075_by-client.md
Normal file
22
docs/Packets/C1-10-WalkRequest075_by-client.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# C1 10 - WalkRequest075 (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player wants to walk on the game map.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The player gets moved on the map, visible for other surrounding players.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x10 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | SourceX |
|
||||||
|
| 4 | 1 | Byte | | SourceY |
|
||||||
|
| 5 | 4 bit | Byte | | StepCount |
|
||||||
|
| 5 | 4 bit | Byte | | TargetRotation |
|
||||||
|
| 6 | | Binary | | Directions; The directions of the walking path. The target is calculated by taking the source coordinates and applying the directions to it. |
|
||||||
20
docs/Packets/C1-11-HitRequest_by-client.md
Normal file
20
docs/Packets/C1-11-HitRequest_by-client.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# C1 11 - HitRequest (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player attacks a target without using a skill.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
Damage is calculated and the target is hit, if the attack was successful. A response is sent back with the caused damage, and all surrounding players get an animation message.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 7 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x11 | Packet header - packet type identifier |
|
||||||
|
| 3 | 2 | ShortBigEndian | | TargetId |
|
||||||
|
| 5 | 1 | Byte | | AttackAnimation |
|
||||||
|
| 6 | 1 | Byte | | LookingDirection |
|
||||||
42
docs/Packets/C1-11-ObjectHitExtended_by-server.md
Normal file
42
docs/Packets/C1-11-ObjectHitExtended_by-server.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# C1 11 - ObjectHitExtended (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
An object got hit in two cases: 1. When the own player is hit; 2. When the own player attacked some other object which got hit.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The damage is shown at the object which received the hit.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 16 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x11 | Packet header - packet type identifier |
|
||||||
|
| 3 << 0 | 4 bit | DamageKind | | Kind |
|
||||||
|
| 3 << 4 | 1 bit | Boolean | | IsRageFighterStreakHit |
|
||||||
|
| 3 << 5 | 1 bit | Boolean | | IsRageFighterStreakFinalHit |
|
||||||
|
| 3 << 6 | 1 bit | Boolean | | IsDoubleDamage |
|
||||||
|
| 3 << 7 | 1 bit | Boolean | | IsTripleDamage |
|
||||||
|
| 4 | 2 | ShortLittleEndian | | ObjectId |
|
||||||
|
| 6 | 1 | Byte | | HealthStatus; Gets or sets the status of the remaining health in fractions of 1/250. |
|
||||||
|
| 7 | 1 | Byte | | ShieldStatus; Gets or sets the status of the remaining shield in fractions of 1/250. |
|
||||||
|
| 8 | 4 | IntegerLittleEndian | | HealthDamage |
|
||||||
|
| 12 | 4 | IntegerLittleEndian | | ShieldDamage |
|
||||||
|
|
||||||
|
### DamageKind Enum
|
||||||
|
|
||||||
|
Defines the kind of the damage.
|
||||||
|
|
||||||
|
| Value | Name | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| 0 | NormalRed | Red color, used by normal damage. |
|
||||||
|
| 1 | IgnoreDefenseCyan | Cyan color, usually used by ignore defense damage. |
|
||||||
|
| 2 | ExcellentLightGreen | Light green color, usually used by excellent damage. |
|
||||||
|
| 3 | CriticalBlue | Blue color, usually used by critical damage. |
|
||||||
|
| 4 | ReflectedLightPink | Light pink color, usually used by reflected damage. |
|
||||||
|
| 5 | PoisonDarkGreen | Dark green color, usually used by poison damage. |
|
||||||
|
| 6 | DarkPink | Dark pink color. |
|
||||||
|
| 7 | White | White color. |
|
||||||
41
docs/Packets/C1-11-ObjectHit_by-server.md
Normal file
41
docs/Packets/C1-11-ObjectHit_by-server.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# C1 11 - ObjectHit (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
An object got hit in two cases: 1. When the own player is hit; 2. When the own player attacked some other object which got hit.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The damage is shown at the object which received the hit.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 10 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x11 | Packet header - packet type identifier |
|
||||||
|
| 2 | 1 | Byte | | HeaderCode |
|
||||||
|
| 3 | 2 | ShortBigEndian | | ObjectId |
|
||||||
|
| 5 | 2 | ShortBigEndian | | HealthDamage |
|
||||||
|
| 7 << 0 | 4 bit | DamageKind | | Kind |
|
||||||
|
| 7 << 4 | 1 bit | Boolean | | IsRageFighterStreakHit |
|
||||||
|
| 7 << 5 | 1 bit | Boolean | | IsRageFighterStreakFinalHit |
|
||||||
|
| 7 << 6 | 1 bit | Boolean | | IsDoubleDamage |
|
||||||
|
| 7 << 7 | 1 bit | Boolean | | IsTripleDamage |
|
||||||
|
| 8 | 2 | ShortBigEndian | | ShieldDamage |
|
||||||
|
|
||||||
|
### DamageKind Enum
|
||||||
|
|
||||||
|
Defines the kind of the damage.
|
||||||
|
|
||||||
|
| Value | Name | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| 0 | NormalRed | Red color, used by normal damage. |
|
||||||
|
| 1 | IgnoreDefenseCyan | Cyan color, usually used by ignore defense damage. |
|
||||||
|
| 2 | ExcellentLightGreen | Light green color, usually used by excellent damage. |
|
||||||
|
| 3 | CriticalBlue | Blue color, usually used by critical damage. |
|
||||||
|
| 4 | ReflectedLightPink | Light pink color, usually used by reflected damage. |
|
||||||
|
| 5 | PoisonDarkGreen | Dark green color, usually used by poison damage. |
|
||||||
|
| 6 | DarkPink | Dark pink color. |
|
||||||
|
| 7 | White | White color. |
|
||||||
29
docs/Packets/C1-14-MapObjectOutOfScope_by-server.md
Normal file
29
docs/Packets/C1-14-MapObjectOutOfScope_by-server.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# C1 14 - MapObjectOutOfScope (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
One or more objects (player, npc, etc.) on the map got out of scope, e.g. when the own player moved away from it/them or the object itself moved.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The game client removes the objects from the game map.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x14 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | ObjectCount |
|
||||||
|
| 4 | ObjectId.Length * ObjectCount | Array of ObjectId | | Objects |
|
||||||
|
|
||||||
|
### ObjectId Structure
|
||||||
|
|
||||||
|
Contains the id of a object.
|
||||||
|
|
||||||
|
Length: 2 Bytes
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 2 | ShortBigEndian | | Id |
|
||||||
19
docs/Packets/C1-15-InstantMoveRequest_by-client.md
Normal file
19
docs/Packets/C1-15-InstantMoveRequest_by-client.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 15 - InstantMoveRequest (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
It's sent when the player performs specific skills.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
Usually, the player is moved instantly to the specified coordinates on the current map. In OpenMU, this request is not handled, because it allows hackers to "teleport" to any coordinates.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 5 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x15 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | TargetX |
|
||||||
|
| 4 | 1 | Byte | | TargetY |
|
||||||
21
docs/Packets/C1-15-ObjectMoved_by-server.md
Normal file
21
docs/Packets/C1-15-ObjectMoved_by-server.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# C1 15 - ObjectMoved (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
An object in the observed scope (including the own player) moved instantly.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The position of the object is updated on client side.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 8 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x15 | Packet header - packet type identifier |
|
||||||
|
| 2 | 1 | Byte | | HeaderCode |
|
||||||
|
| 3 | 2 | ShortBigEndian | | ObjectId |
|
||||||
|
| 5 | 1 | Byte | | PositionX |
|
||||||
|
| 6 | 1 | Byte | | PositionY |
|
||||||
20
docs/Packets/C1-17-ObjectGotKilled_by-server.md
Normal file
20
docs/Packets/C1-17-ObjectGotKilled_by-server.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# C1 17 - ObjectGotKilled (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
An observed object was killed.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The object is shown as dead.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 9 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x17 | Packet header - packet type identifier |
|
||||||
|
| 3 | 2 | ShortBigEndian | | KilledId |
|
||||||
|
| 5 | 2 | ShortBigEndian | | SkillId |
|
||||||
|
| 7 | 2 | ShortBigEndian | | KillerId |
|
||||||
19
docs/Packets/C1-18-AnimationRequest_by-client.md
Normal file
19
docs/Packets/C1-18-AnimationRequest_by-client.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 18 - AnimationRequest (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player does any kind of animation.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The animation number and rotation is forwarded to all surrounding players.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 5 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x18 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | Rotation |
|
||||||
|
| 4 | 1 | Byte | | AnimationNumber |
|
||||||
21
docs/Packets/C1-18-ObjectAnimation_by-server.md
Normal file
21
docs/Packets/C1-18-ObjectAnimation_by-server.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# C1 18 - ObjectAnimation (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
An object performs an animation.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The animation is shown for the specified object.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 9 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x18 | Packet header - packet type identifier |
|
||||||
|
| 3 | 2 | ShortBigEndian | | ObjectId |
|
||||||
|
| 5 | 1 | Byte | | Direction |
|
||||||
|
| 6 | 1 | Byte | | Animation |
|
||||||
|
| 7 | 2 | ShortBigEndian | | TargetId |
|
||||||
21
docs/Packets/C1-19-SkillAnimation075_by-server.md
Normal file
21
docs/Packets/C1-19-SkillAnimation075_by-server.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# C1 19 - SkillAnimation075 (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
An object performs a skill which is directly targeted to another object.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The animation is shown on the user interface.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 8 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x19 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | SkillId |
|
||||||
|
| 4 | 2 | ShortBigEndian | | PlayerId |
|
||||||
|
| 6 | 2 | ShortBigEndian | | TargetId |
|
||||||
|
| 6 << 7 | 1 bit | Boolean | | EffectApplied |
|
||||||
19
docs/Packets/C1-19-TargetedSkill075_by-client.md
Normal file
19
docs/Packets/C1-19-TargetedSkill075_by-client.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 19 - TargetedSkill075 (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player performs a skill with a target, e.g. attacking or buffing.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
Damage is calculated and the target is hit, if the attack was successful. A response is sent back with the caused damage, and all surrounding players get an animation message.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 6 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x19 | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | SkillIndex; The index of the skill in the skill list. |
|
||||||
|
| 4 | 2 | ShortBigEndian | | TargetId |
|
||||||
19
docs/Packets/C1-1B-MagicEffectCancelRequest_by-client.md
Normal file
19
docs/Packets/C1-1B-MagicEffectCancelRequest_by-client.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 1B - MagicEffectCancelRequest (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player cancels a specific magic effect of a skill, usually 'Infinity Arrow' and 'Wizardy Enhance'.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The effect is cancelled and an update is sent to the player and all surrounding players.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 7 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x1B | Packet header - packet type identifier |
|
||||||
|
| 3 | 2 | ShortBigEndian | | SkillId |
|
||||||
|
| 5 | 2 | ShortBigEndian | | PlayerId |
|
||||||
19
docs/Packets/C1-1B-MagicEffectCancelled075_by-server.md
Normal file
19
docs/Packets/C1-1B-MagicEffectCancelled075_by-server.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 1B - MagicEffectCancelled075 (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player cancelled a specific magic effect of a skill (Infinity Arrow, Wizardry Enhance), or an effect was removed due a timeout (Ice, Poison) or antidote.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The effect is removed from the target object.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 6 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x1B | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | SkillId |
|
||||||
|
| 4 | 2 | ShortBigEndian | | TargetId |
|
||||||
19
docs/Packets/C1-1B-MagicEffectCancelled_by-server.md
Normal file
19
docs/Packets/C1-1B-MagicEffectCancelled_by-server.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# C1 1B - MagicEffectCancelled (by server)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
A player cancelled a specific magic effect of a skill (Infinity Arrow, Wizardry Enhance), or an effect was removed due a timeout (Ice, Poison) or antidote.
|
||||||
|
|
||||||
|
## Causes the following actions on the client side
|
||||||
|
|
||||||
|
The effect is removed from the target object.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | 7 | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x1B | Packet header - packet type identifier |
|
||||||
|
| 3 | 2 | ShortBigEndian | | SkillId |
|
||||||
|
| 5 | 2 | ShortBigEndian | | TargetId |
|
||||||
32
docs/Packets/C1-1D-AreaSkillHit075_by-client.md
Normal file
32
docs/Packets/C1-1D-AreaSkillHit075_by-client.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# C1 1D - AreaSkillHit075 (by client)
|
||||||
|
|
||||||
|
## Is sent when
|
||||||
|
|
||||||
|
An area skill was performed and the client decided to hit one or more targets.
|
||||||
|
|
||||||
|
## Causes the following actions on the server side
|
||||||
|
|
||||||
|
The server is calculating the damage and applying it to the targets. The attacker gets a response back with the caused damage.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
|
||||||
|
| 1 | 1 | Byte | | Packet header - length of the packet |
|
||||||
|
| 2 | 1 | Byte | 0x1D | Packet header - packet type identifier |
|
||||||
|
| 3 | 1 | Byte | | SkillIndex; The index of the skill in the skill list. |
|
||||||
|
| 4 | 1 | Byte | | TargetX |
|
||||||
|
| 5 | 1 | Byte | | TargetY |
|
||||||
|
| 6 | 1 | Byte | | TargetCount; The number of targets which are hit. |
|
||||||
|
| 7 | TargetData.Length * TargetCount | Array of TargetData | | Targets |
|
||||||
|
|
||||||
|
### TargetData Structure
|
||||||
|
|
||||||
|
Contains the data of the target
|
||||||
|
|
||||||
|
Length: 2 Bytes
|
||||||
|
|
||||||
|
| Index | Length | Data Type | Value | Description |
|
||||||
|
|-------|--------|-----------|-------|-------------|
|
||||||
|
| 0 | 2 | ShortBigEndian | | TargetId |
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user