first push
This commit is contained in:
parent
78ec513ea3
commit
e08a9d7968
64 changed files with 942476 additions and 12 deletions
26
README.md
26
README.md
|
@ -1,9 +1,11 @@
|
|||
# CipherSR
|
||||
#### Honkai: Star Rail server emulator (3.3 beta) written in Zig.
|
||||
# JingliuSR
|
||||
#### Honkai: Star Rail server emulator (3.4 beta) written in Zig.
|
||||
|
||||
# Saber who??? trash bin who???
|
||||

|
||||
|
||||
## Requirements
|
||||
[Zig 0.13.0](https://ziglang.org/download/) and
|
||||
[Zig 0.13.0 x64](https://ziglang.org/download/0.13.0/zig-windows-x86_64-0.13.0.zip) and
|
||||
[Proxy](https://git.xeondev.com/YYHEggEgg/FireflySR.Tool.Proxy/releases)
|
||||
|
||||
## Running
|
||||
|
@ -11,34 +13,34 @@
|
|||
|
||||
Windows:
|
||||
```
|
||||
git clone https://git.xeondev.com/castorice-sr/cipher-sr
|
||||
cd cipher-sr
|
||||
start zig build run-dispatch
|
||||
start zig build run-gameserver
|
||||
git clone https://git.xeondev.com/HonkaiSlopRail/jingliu-sr
|
||||
cd jingliu-sr
|
||||
zig build run-dispatch
|
||||
zig build run-
|
||||
```
|
||||
Then open Proxy then open client
|
||||
|
||||
Linux:
|
||||
```
|
||||
git clone https://git.xeondev.com/castorice-sr/cipher-sr
|
||||
cd cipher-sr
|
||||
git clone https://git.xeondev.com/HonkaiSlopRail/jingliu-sr
|
||||
cd jingliu-sr
|
||||
zig build run-dispatch & zig build run-gameserver
|
||||
```
|
||||
Then open Proxy then open client
|
||||
|
||||
### Using Pre-built Binaries
|
||||
Navigate to the [Releases](https://git.xeondev.com/castorice-sr/cipher-sr/releases)
|
||||
Navigate to the [Releases](https://git.xeondev.com/HonkaiSlopRail/jingliu-sr/releases)
|
||||
page and download the latest release for your platform.
|
||||
|
||||
## Connecting
|
||||
[Get 3.2.52 client](https://gofile.io/d/Q7fSQm)
|
||||
[Get 3.3.51 client](https://gofile.io/d/tWhXrJ)
|
||||
|
||||
## Functionality (work in progress)
|
||||
- Login and player spawn
|
||||
- Test battle via calyx
|
||||
- MOC/PF/AS simulator
|
||||
- Gacha simulator
|
||||
- Support command for Sillyism
|
||||
- Support command for Sillyism (there are some bugs right now )
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
64
build.zig
Normal file
64
build.zig
Normal file
|
@ -0,0 +1,64 @@
|
|||
const std = @import("std");
|
||||
const protobuf = @import("protobuf");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const dep_opts = .{ .target = target, .optimize = optimize };
|
||||
|
||||
const protobuf_dep = b.dependency("protobuf", dep_opts);
|
||||
|
||||
if (std.fs.cwd().access("protocol/StarRail.proto", .{})) {
|
||||
const protoc_step = protobuf.RunProtocStep.create(b, protobuf_dep.builder, target, .{
|
||||
.destination_directory = b.path("protocol/src"),
|
||||
.source_files = &.{
|
||||
"protocol/StarRail.proto",
|
||||
},
|
||||
.include_directories = &.{},
|
||||
});
|
||||
|
||||
b.getInstallStep().dependOn(&protoc_step.step);
|
||||
} else |_| {} // don't invoke protoc if proto definition doesn't exist
|
||||
|
||||
const dispatch = b.dependency("dispatch", dep_opts);
|
||||
b.installArtifact(dispatch.artifact("dispatch"));
|
||||
|
||||
const gameserver = b.dependency("gameserver", dep_opts);
|
||||
b.installArtifact(gameserver.artifact("gameserver"));
|
||||
|
||||
// "run-dispatch" command
|
||||
const dispatch_cmd = b.addRunArtifact(dispatch.artifact("dispatch"));
|
||||
dispatch_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
if (b.args) |args| {
|
||||
dispatch_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const dispatch_step = b.step("run-dispatch", "Run the dispatch server");
|
||||
dispatch_step.dependOn(&dispatch_cmd.step);
|
||||
|
||||
// "run-gameserver" command
|
||||
const gameserver_cmd = b.addRunArtifact(gameserver.artifact("gameserver"));
|
||||
gameserver_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
if (b.args) |args| {
|
||||
gameserver_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const gameserver_step = b.step("run-gameserver", "Run the game server");
|
||||
gameserver_step.dependOn(&gameserver_cmd.step);
|
||||
// "gen-proto"
|
||||
const gen_proto = b.step("gen-proto", "generates zig files from protocol buffer definitions");
|
||||
|
||||
const protoc_step = protobuf.RunProtocStep.create(b, protobuf_dep.builder, target, .{
|
||||
// out directory for the generated zig files
|
||||
.destination_directory = b.path("protocol/src"),
|
||||
.source_files = &.{
|
||||
"protocol/StarRail.proto",
|
||||
},
|
||||
.include_directories = &.{},
|
||||
});
|
||||
|
||||
gen_proto.dependOn(&protoc_step.step);
|
||||
}
|
15
build.zig.zon
Normal file
15
build.zig.zon
Normal file
|
@ -0,0 +1,15 @@
|
|||
.{
|
||||
.name = "JingliuSR",
|
||||
.version = "0.0.1",
|
||||
.minimum_zig_version = "0.13.0",
|
||||
.dependencies = .{
|
||||
.dispatch = .{ .path = "dispatch" },
|
||||
.gameserver = .{ .path = "gameserver" },
|
||||
.protocol = .{ .path = "protocol" },
|
||||
.protobuf = .{
|
||||
.url = "https://github.com/Arwalk/zig-protobuf/archive/7c49ed66e029c9c7e6253b3d6d256118745550a4.tar.gz",
|
||||
.hash = "122063ee7ff32a3c1aefd91a46a9fc23df0571949c3a02e2f44d39afbad0b53018a3",
|
||||
},
|
||||
},
|
||||
.paths = .{""},
|
||||
}
|
328
config.json
Normal file
328
config.json
Normal file
|
@ -0,0 +1,328 @@
|
|||
{
|
||||
"avatar_config": [
|
||||
{
|
||||
"name": "Jingliu",
|
||||
"id": 1212,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23014,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61041,15,1,4,5:1:0,6:3:5,8:1:1,9:4:4",
|
||||
"61022,15,1,4,3:1:1,6:3:3,8:1:1,9:3:3",
|
||||
"61043,15,5,4,6:1:1,8:3:3,10:3:3,12:2:1",
|
||||
"61024,15,4,4,2:1:2,5:1:1,8:4:4,9:3:0",
|
||||
"63095,15,6,4,2:1:0,3:3:4,8:2:3,11:2:4",
|
||||
"63096,15,2,4,1:1:0,2:2:4,7:3:1,9:2:3"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "Silver Wolf",
|
||||
"id": 1006,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23007,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61141,15,1,4,2:3:2,4:2:3,7:2:1,11:1:2",
|
||||
"61142,15,1,4,3:1:0,6:1:1,7:4:4,9:2:0",
|
||||
"61113,15,7,4,2:1:2,6:3:2,7:3:1,11:1:0",
|
||||
"61114,15,4,4,3:1:2,4:3:3,10:3:4,11:2:1",
|
||||
"63125,15,1,4,2:2:4,7:3:1,11:2:2,12:2:3",
|
||||
"63126,15,2,4,6:1:0,7:2:1,9:3:1,10:2:2"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "Kafka",
|
||||
"id": 1005,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23006,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61161,15,1,4,5:1:1,6:2:2,7:3:1,8:2:2",
|
||||
"61162,15,1,4,1:2:2,5:2:2,9:2:2,10:2:3",
|
||||
"61163,15,2,4,7:3:1,8:1:1,10:2:2,11:2:3",
|
||||
"61164,15,4,4,1:1:0,8:2:0,9:2:1,11:3:4",
|
||||
"63115,15,7,4,1:3:4,2:1:2,8:1:0,9:3:0",
|
||||
"63116,15,4,4,1:2:2,8:3:0,11:1:2,12:2:4"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "Saber",
|
||||
"id": 1014,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 6,
|
||||
"lightcone": {
|
||||
"id": 23045,
|
||||
"rank": 5,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61261,15,1,4,5:2:2,7:1:1,8:3:3,9:3:3",
|
||||
"61262,15,1,4,9:1:1,7:3:3,5:3:3,8:2:2",
|
||||
"61263,15,5,4,7:2:2,8:3:3,5:3:3,4:1:1",
|
||||
"61264,15,4,4,8:2:2,9:3:3,5:2:2,4:2:2",
|
||||
"63095,15,8,4,9:2:2,8:1:1,5:3:3,7:3:3",
|
||||
"63096,15,4,4,9:2:2,8:2:2,7:3:3,4:2:2"
|
||||
],
|
||||
"use_technique": true
|
||||
},
|
||||
{
|
||||
"name": "Archer",
|
||||
"id": 1015,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23046,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61261,15,1,4,8:2:2,2:3:3,4:1:1,12:3:3",
|
||||
"61262,15,1,4,10:2:2,11:3:3,12:3:3,6:1:1",
|
||||
"61263,15,5,4,4:2:2,10:3:3,11:2:2,12:2:2",
|
||||
"61264,15,2,4,10:2:2,6:2:2,9:4:4,2:1:1",
|
||||
"63145,15,9,4,4:1:1,6:4:4,9:1:1,5:3:3",
|
||||
"63146,15,4,4,1:3:3,10:3:3,9:1:1,11:2:2"
|
||||
],
|
||||
"use_technique": true
|
||||
},
|
||||
{
|
||||
"name": "Phainon",
|
||||
"id": 1408,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23044,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61261,15,1,4,6:1:1,9:3:3,12:3:3,4:2:2",
|
||||
"61262,15,1,4,9:4:4,11:1:1,5:2:2,8:2:2",
|
||||
"61263,15,5,4,3:2:2,2:2:2,5:4:4,6:1:1",
|
||||
"61264,15,2,4,10:1:1,12:3:3,8:1:1,4:4:4",
|
||||
"63225,15,4,4,9:1:1,4:2:2,6:2:2,3:4:4",
|
||||
"63226,15,4,4,1:3:3,8:2:2,2:2:2,3:2:2"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "Hyacine",
|
||||
"id": 1409,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23042,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61251,15,1,4,3:1:2,4:3:1,7:1:0,9:3:2",
|
||||
"61252,15,1,4,1:2:4,7:3:1,9:2:0,12:1:2",
|
||||
"61253,15,6,4,6:2:2,7:3:1,9:1:2,11:2:3",
|
||||
"61254,15,4,4,1:3:2,5:1:1,9:2:2,11:2:2",
|
||||
"63205,15,1,4,1:1:0,6:1:2,7:3:1,9:3:2",
|
||||
"63206,15,3,4,3:1:0,6:2:2,7:4:4,9:1:0"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "Castorice",
|
||||
"id": 1407,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23040,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61241,15,1,4,5:2:3,8:2:1,9:3:3,12:1:0",
|
||||
"61242,15,1,4,4:3:2,5:1:2,6:1:0,9:3:2",
|
||||
"61243,15,5,4,1:1:0,4:1:0,8:3:3,10:3:3",
|
||||
"61244,15,1,4,1:1:1,2:2:3,8:2:0,9:3:5",
|
||||
"63195,15,1,4,1:3:6,2:1:0,8:2:2,9:2:1",
|
||||
"63196,15,3,4,3:1:1,8:4:5,9:3:1,10:1:1"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "Traiblazer",
|
||||
"id": 8008,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 6,
|
||||
"lightcone": {
|
||||
"id": 24005,
|
||||
"rank": 5,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61231,15,1,4,3:1:0,7:2:4,9:2:4,10:3:1",
|
||||
"61232,15,1,4,7:2:1,9:4:2,10:1:1,11:1:2",
|
||||
"61233,15,5,4,4:2:2,7:4:1,10:1:1,12:2:1",
|
||||
"61234,15,4,4,3:1:8,4:2:2,9:3:2,11:2:1",
|
||||
"63085,15,1,4,1:1:2,5:3:1,7:2:1,9:2:2",
|
||||
"63086,15,2,4,1:3:4,2:2:2,9:1:1,10:2:3"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "March 7th",
|
||||
"id": 1224,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 6,
|
||||
"lightcone": {
|
||||
"id": 24001,
|
||||
"rank": 5,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61021,15,1,4,5:1:0,8:2:4,9:4:6,10:2:2",
|
||||
"61202,15,1,4,5:3:3,8:2:4,9:1:1,11:2:3",
|
||||
"61023,15,5,4,2:1:1,7:1:0,8:4:4,10:3:4",
|
||||
"61204,15,2,4,3:1:0,6:1:0,8:5:2,9:2:1",
|
||||
"63095,15,2,4,1:2:3,8:2:2,9:2:3,11:3:3",
|
||||
"63096,15,2,4,5:3:3,6:2:4,9:2:0,11:2:3"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "Huohuo",
|
||||
"id": 1217,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23017,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61141,15,1,4,4:2:3,8:3:1,10:1:1,12:2:2",
|
||||
"61142,15,1,4,1:2:0,4:1:2,7:3:3,11:2:3",
|
||||
"61143,15,6,4,1:2:3,4:2:2,9:1:2,10:3:5",
|
||||
"61144,15,4,4,1:1:1,4:3:4,6:1:0,11:3:2",
|
||||
"63085,15,1,4,1:3:4,7:2:1,11:3:3,12:1:0",
|
||||
"63086,15,2,4,2:1:2,3:3:5,11:2:3,12:2:2"
|
||||
],
|
||||
"use_technique": false
|
||||
},
|
||||
{
|
||||
"name": "Sunday",
|
||||
"id": 1313,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23034,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61211,15,1,4,5:3:3,7:3:3,8:1:1,9:2:2",
|
||||
"61212,15,1,4,9:4:4,7:2:2,5:2:2,8:1:1",
|
||||
"61213,15,5,4,7:2:2,8:1:1,5:4:4,4:2:2",
|
||||
"61214,15,4,4,8:3:3,9:2:2,5:2:2,4:2:2",
|
||||
"63175,15,1,4,9:2:2,8:1:1,5:3:3,7:3:3",
|
||||
"63176,15,2,4,9:4:4,8:1:1,7:2:2,4:2:2"
|
||||
],
|
||||
"use_technique": true
|
||||
},
|
||||
{
|
||||
"name": "Tribbie",
|
||||
"id": 1403,
|
||||
"hp": 100,
|
||||
"sp": 50,
|
||||
"level": 80,
|
||||
"promotion": 6,
|
||||
"rank": 0,
|
||||
"lightcone": {
|
||||
"id": 23038,
|
||||
"rank": 1,
|
||||
"level": 80,
|
||||
"promotion": 6
|
||||
},
|
||||
"relics": [
|
||||
"61241,15,1,4,8:2:1,9:2:4,11:2:2,12:2:2",
|
||||
"61242,15,1,4,3:1:0,4:2:0,6:1:8,9:3:2",
|
||||
"61243,15,5,4,3:2:4,8:3:2,10:1:0,11:2:3",
|
||||
"61244,15,1,4,1:2:3,3:2:2,8:2:2,9:2:2",
|
||||
"63195,15,1,4,1:2:4,5:1:1,8:4:4,9:1:1",
|
||||
"63196,15,2,4,4:1:1,8:3:5,9:1:2,12:3:3"
|
||||
],
|
||||
"use_technique": true
|
||||
}
|
||||
],
|
||||
"battle_config": {
|
||||
"battle_id": 1,
|
||||
"stage_id": 201012311,
|
||||
"cycle_count": 30,
|
||||
"monster_wave": [
|
||||
[
|
||||
4015011
|
||||
]
|
||||
],
|
||||
"monster_level": 95,
|
||||
"blessings": []
|
||||
}
|
||||
}
|
41
dispatch/build.zig
Normal file
41
dispatch/build.zig
Normal file
|
@ -0,0 +1,41 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const httpz = b.dependency("httpz", .{
|
||||
.optimize = optimize,
|
||||
.target = target,
|
||||
});
|
||||
|
||||
const protocol = b.dependency("protocol", .{});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "dispatch",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const tls12 = b.dependency("tls12", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
exe.root_module.addImport("tls12", tls12.module("zig-tls12"));
|
||||
exe.root_module.addImport("httpz", httpz.module("httpz"));
|
||||
exe.root_module.addImport("protocol", protocol.module("protocol"));
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
}
|
23
dispatch/build.zig.zon
Normal file
23
dispatch/build.zig.zon
Normal file
|
@ -0,0 +1,23 @@
|
|||
.{
|
||||
.name = "dispatch",
|
||||
.version = "0.0.1",
|
||||
.minimum_zig_version = "0.13.0",
|
||||
.dependencies = .{
|
||||
.httpz = .{
|
||||
.url = "https://github.com/karlseguin/http.zig/archive/44b97984c6a9613634e238d27ca6cdff4d4abebd.tar.gz",
|
||||
.hash = "122034afde1b4ff5971787929d1a4a8ef175e1c18fe0cf4ffc1af1ce0c95c7b6be7b",
|
||||
},
|
||||
.protocol = .{
|
||||
.path = "../protocol",
|
||||
},
|
||||
.tls12 = .{
|
||||
.url = "https://github.com/melonedo/zig-tls12/archive/f2cbb84.tar.gz",
|
||||
.hash = "12202bb2c3824deecd4ccd666ca3dcb9c92c2c68698afdb92b382c0f5cb1b86da8bc",
|
||||
},
|
||||
},
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
},
|
||||
}
|
219
dispatch/src/authentication.zig
Normal file
219
dispatch/src/authentication.zig
Normal file
|
@ -0,0 +1,219 @@
|
|||
const std = @import("std");
|
||||
const httpz = @import("httpz");
|
||||
|
||||
pub fn onShieldLogin(req: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onShieldLogin: {any}", .{req.body_len});
|
||||
//std.log.debug("onShieldLogin BODY: {any}", .{req}); game breaking
|
||||
|
||||
try res.json(.{
|
||||
.data = .{
|
||||
.account = .{
|
||||
.area_code = "**",
|
||||
.email = "ReversedRoooms@StarRail.com",
|
||||
.country = "RU",
|
||||
.is_email_verify = "1",
|
||||
.token = "aa",
|
||||
.uid = "1337",
|
||||
},
|
||||
.device_grant_required = false,
|
||||
.reactivate_required = false,
|
||||
.realperson_required = false,
|
||||
.safe_mobilerequired = false,
|
||||
},
|
||||
.message = "OK",
|
||||
.retcode = 0,
|
||||
}, .{});
|
||||
}
|
||||
|
||||
pub fn onShieldVerify(req: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onShieldVerify: {any}", .{req.body_len});
|
||||
|
||||
try res.json(.{
|
||||
.data = .{
|
||||
.account = .{
|
||||
.area_code = "**",
|
||||
.email = "ReversedRoooms@StarRail.com",
|
||||
.country = "RU",
|
||||
.is_email_verify = "1",
|
||||
.token = "aa",
|
||||
.uid = "1337",
|
||||
},
|
||||
.device_grant_required = false,
|
||||
.reactivate_required = false,
|
||||
.realperson_required = false,
|
||||
.safe_mobilerequired = false,
|
||||
},
|
||||
.message = "OK",
|
||||
.retcode = 0,
|
||||
}, .{});
|
||||
}
|
||||
|
||||
pub fn onVerifyLogin(req: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onVerifyLogin: {any}", .{req.body_len});
|
||||
|
||||
var token: []const u8 = "aa";
|
||||
var uid: []const u8 = "1337";
|
||||
if (try req.jsonObject()) |t| {
|
||||
if (t.get("token")) |token_value| {
|
||||
token = token_value.string;
|
||||
}
|
||||
if (t.get("uid")) |uid_value| {
|
||||
uid = uid_value.string;
|
||||
}
|
||||
}
|
||||
|
||||
try res.json(.{
|
||||
.retcode = 0,
|
||||
.message = "OK",
|
||||
.data = .{
|
||||
.account = .{
|
||||
.area_code = "**",
|
||||
.country = "CN",
|
||||
.is_email_verify = "1",
|
||||
.email = "ReversedRoooms@StarRail.com",
|
||||
.token = token,
|
||||
.uid = uid,
|
||||
},
|
||||
},
|
||||
}, .{});
|
||||
}
|
||||
|
||||
pub fn onComboTokenReq(req: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onComboTokenReq: {any}", .{req.body_len});
|
||||
|
||||
try res.json(.{
|
||||
.data = .{
|
||||
.account_type = 1,
|
||||
.open_id = "1337",
|
||||
.combo_id = "1337",
|
||||
.combo_token = "9065ad8507d5a1991cb6fddacac5999b780bbd92",
|
||||
.heartbeat = false,
|
||||
.data = "{\"guest\": false}",
|
||||
},
|
||||
.message = "OK",
|
||||
.retcode = 0,
|
||||
}, .{});
|
||||
}
|
||||
|
||||
pub fn onRiskyApiCheck(req: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onRiskyApiCheck: {any}", .{req.body_len});
|
||||
|
||||
try res.json(.{
|
||||
.retcode = 0,
|
||||
.message = "OK",
|
||||
.data = .{
|
||||
.id = "06611ed14c3131a676b19c0d34c0644b",
|
||||
.action = "ACTION_NONE",
|
||||
.geetest = null,
|
||||
},
|
||||
}, .{});
|
||||
}
|
||||
|
||||
pub fn onGetConfig(_: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onGetConfig: ", .{});
|
||||
|
||||
try res.json(.{
|
||||
.retcode = 0,
|
||||
.message = "OK",
|
||||
.data = .{
|
||||
.protocol = true,
|
||||
.qr_enabled = false,
|
||||
.log_level = "INFO",
|
||||
.announce_url = "",
|
||||
.push_alias_type = 0,
|
||||
.disable_ysdk_guard = true,
|
||||
.enable_announce_pic_popup = false,
|
||||
.app_name = "崩<EFBFBD>??RPG",
|
||||
.qr_enabled_apps = .{
|
||||
.bbs = false,
|
||||
.cloud = false,
|
||||
},
|
||||
.qr_app_icons = .{
|
||||
.app = "",
|
||||
.bbs = "",
|
||||
.cloud = "",
|
||||
},
|
||||
.qr_cloud_display_name = "",
|
||||
.enable_user_center = true,
|
||||
.functional_switch_configs = .{},
|
||||
},
|
||||
}, .{});
|
||||
}
|
||||
|
||||
pub fn onLoadConfig(_: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onLoadConfig: ", .{});
|
||||
|
||||
try res.json(.{
|
||||
.retcode = 0,
|
||||
.message = "OK",
|
||||
.data = .{
|
||||
.id = 24,
|
||||
.game_key = "hkrpg_global",
|
||||
.client = "PC",
|
||||
.identity = "I_IDENTITY",
|
||||
.guest = false,
|
||||
.ignore_versions = "",
|
||||
.scene = "S_NORMAL",
|
||||
.name = "崩<EFBFBD>??RPG",
|
||||
.disable_regist = false,
|
||||
.enable_email_captcha = false,
|
||||
.thirdparty = .{ "fb", "tw", "gl", "ap" },
|
||||
.disable_mmt = false,
|
||||
.server_guest = false,
|
||||
.thirdparty_ignore = .{},
|
||||
.enable_ps_bind_account = false,
|
||||
.thirdparty_login_configs = .{
|
||||
.tw = .{
|
||||
.token_type = "TK_GAME_TOKEN",
|
||||
.game_token_expires_in = 2592000,
|
||||
},
|
||||
.ap = .{
|
||||
.token_type = "TK_GAME_TOKEN",
|
||||
.game_token_expires_in = 604800,
|
||||
},
|
||||
.fb = .{
|
||||
.token_type = "TK_GAME_TOKEN",
|
||||
.game_token_expires_in = 2592000,
|
||||
},
|
||||
.gl = .{
|
||||
.token_type = "TK_GAME_TOKEN",
|
||||
.game_token_expires_in = 604800,
|
||||
},
|
||||
},
|
||||
.initialize_firebase = false,
|
||||
.bbs_auth_login = false,
|
||||
.bbs_auth_login_ignore = {},
|
||||
.fetch_instance_id = false,
|
||||
.enable_flash_login = false,
|
||||
},
|
||||
}, .{});
|
||||
}
|
||||
|
||||
pub fn onappLoginByPassword(req: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onappLoginByPassword: {any}", .{req.body_len});
|
||||
|
||||
try res.json(.{
|
||||
.retcode = 0,
|
||||
.message = "OK",
|
||||
.data = .{
|
||||
.bind_email_action_ticket = "",
|
||||
.ext_user_info = .{
|
||||
.birth = "0",
|
||||
.guardian_email = "",
|
||||
},
|
||||
.reactivate_action_token = "",
|
||||
.token = .{
|
||||
.token = "aa",
|
||||
.token_type = "1",
|
||||
},
|
||||
.user_info = .{
|
||||
.account_name = "ReversedRooms",
|
||||
.aid = "1337",
|
||||
.area_code = "**",
|
||||
.country = "RU",
|
||||
.email = "ReversedRoooms@StarRail.com",
|
||||
.is_email_verify = "1",
|
||||
},
|
||||
},
|
||||
}, .{});
|
||||
}
|
159
dispatch/src/dispatch.zig
Normal file
159
dispatch/src/dispatch.zig
Normal file
|
@ -0,0 +1,159 @@
|
|||
const std = @import("std");
|
||||
const httpz = @import("httpz");
|
||||
const protocol = @import("protocol");
|
||||
const HttpClient = @import("tls12");
|
||||
const Base64Encoder = @import("std").base64.standard.Encoder;
|
||||
const Base64Decoder = @import("std").base64.standard.Decoder;
|
||||
const hotfixInfo = @import("hotfix.zig");
|
||||
const CNPROD_HOST = "prod-gf-cn-dp01.bhsr.com";
|
||||
const CNBETA_HOST = "beta-release01-cn.bhsr.com";
|
||||
const OSPROD_HOST = "prod-official-asia-dp01.starrails.com";
|
||||
const OSBETA_HOST = "beta-release01-asia.starrails.com";
|
||||
|
||||
pub fn onQueryDispatch(_: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onQueryDispatch", .{});
|
||||
|
||||
var proto = protocol.Dispatch.init(res.arena);
|
||||
|
||||
const region_info = protocol.RegionInfo{
|
||||
.name = .{ .Const = "JingliuSR" },
|
||||
.display_name = .{ .Const = "JingliuSR" },
|
||||
.env_type = .{ .Const = "21" },
|
||||
.title = .{ .Const = "JingliuSR" },
|
||||
.dispatch_url = .{ .Const = "http://127.0.0.1:21000/query_gateway" },
|
||||
};
|
||||
|
||||
try proto.region_list.append(region_info);
|
||||
|
||||
const data = try proto.encode(res.arena);
|
||||
const size = Base64Encoder.calcSize(data.len);
|
||||
const output = try res.arena.alloc(u8, size);
|
||||
_ = Base64Encoder.encode(output, data);
|
||||
|
||||
res.body = output;
|
||||
}
|
||||
|
||||
pub fn onQueryGateway(req: *httpz.Request, res: *httpz.Response) !void {
|
||||
std.log.debug("onQueryGateway", .{});
|
||||
|
||||
var proto = protocol.Gateserver.init(res.arena);
|
||||
const query = try req.query();
|
||||
const version = query.get("version") orelse "";
|
||||
std.log.info("Get Version >> {s}", .{version});
|
||||
const dispatch_seed = query.get("dispatch_seed") orelse "";
|
||||
std.log.info("Get DispatchSeed >> {s}", .{dispatch_seed});
|
||||
const host = selectHost(version);
|
||||
const gatewayUrl = constructUrl(host, version, dispatch_seed);
|
||||
std.log.info("Constructed Gateway URL >> {s}", .{gatewayUrl});
|
||||
const hotfix = try hotfixInfo.Parser(res.arena, "hotfix.json", version);
|
||||
|
||||
var assetBundleUrl: []const u8 = undefined;
|
||||
var exResourceUrl: []const u8 = undefined;
|
||||
var luaUrl: []const u8 = undefined;
|
||||
var iFixUrl: []const u8 = undefined;
|
||||
//var luaVersion: []const u8 = undefined;
|
||||
//var iFixVersion: []const u8 = undefined;
|
||||
|
||||
//HTTP Request
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const allocator = arena.allocator();
|
||||
|
||||
var client = HttpClient{ .allocator = allocator };
|
||||
defer client.deinit();
|
||||
try client.initDefaultProxies(allocator);
|
||||
|
||||
const url = gatewayUrl;
|
||||
|
||||
const uri = try std.Uri.parse(url);
|
||||
var server_header_buffer: [1024 * 1024]u8 = undefined;
|
||||
var gateway_request = try HttpClient.open(&client, .GET, uri, .{
|
||||
.server_header_buffer = &server_header_buffer,
|
||||
.redirect_behavior = @enumFromInt(10),
|
||||
});
|
||||
defer gateway_request.deinit();
|
||||
|
||||
try gateway_request.send();
|
||||
try gateway_request.wait();
|
||||
const gateway_response_body = try gateway_request.reader().readAllAlloc(allocator, 16 * 1024 * 1024);
|
||||
|
||||
//Base64 Decode
|
||||
const decoded_len = try Base64Decoder.calcSizeForSlice(gateway_response_body);
|
||||
const decoded_data = try allocator.alloc(u8, decoded_len);
|
||||
defer allocator.free(decoded_data);
|
||||
try Base64Decoder.decode(decoded_data, gateway_response_body);
|
||||
//Gateserver Protobuf Decode
|
||||
const gateserver_proto = try protocol.Gateserver.decode(decoded_data, res.arena);
|
||||
|
||||
//std.log.info("\x1b[33;1mEncoded Gateway Response >> {s}\x1b[0m", .{gateway_response_body});
|
||||
//std.log.info("\x1b[32;1mDecoded Gateway Response >> {s}\x1b[0m", .{decoded_data});
|
||||
//std.log.info("\x1b[33;1mProtobuf Message >> {}\x1b[0m", .{gateserver_proto});
|
||||
|
||||
assetBundleUrl = hotfix.assetBundleUrl;
|
||||
exResourceUrl = hotfix.exResourceUrl;
|
||||
luaUrl = hotfix.luaUrl;
|
||||
iFixUrl = hotfix.iFixUrl;
|
||||
|
||||
if (assetBundleUrl.len == 0 or exResourceUrl.len == 0 or luaUrl.len == 0 or iFixUrl.len == 0) {
|
||||
assetBundleUrl = gateserver_proto.asset_bundle_url.Owned.str;
|
||||
exResourceUrl = gateserver_proto.ex_resource_url.Owned.str;
|
||||
luaUrl = gateserver_proto.lua_url.Owned.str;
|
||||
iFixUrl = gateserver_proto.ifix_url.Owned.str;
|
||||
|
||||
try hotfixInfo.putValue(version, assetBundleUrl, exResourceUrl, luaUrl, iFixUrl);
|
||||
}
|
||||
|
||||
std.log.info("Get AssetBundleUrl >> {s}", .{assetBundleUrl});
|
||||
std.log.info("Get ExResourceUrl >> {s}", .{exResourceUrl});
|
||||
std.log.info("Get LuaUrl >> {s}", .{luaUrl});
|
||||
std.log.info("Get IFixUrl >> {s}", .{iFixUrl});
|
||||
|
||||
proto.retcode = 0;
|
||||
proto.port = 23301;
|
||||
proto.ip = .{ .Const = "127.0.0.1" };
|
||||
|
||||
proto.asset_bundle_url = .{ .Const = assetBundleUrl };
|
||||
proto.ex_resource_url = .{ .Const = exResourceUrl };
|
||||
proto.lua_url = .{ .Const = luaUrl };
|
||||
|
||||
proto.enable_watermark = true;
|
||||
proto.network_diagnostic = true;
|
||||
proto.enable_android_middle_package = true;
|
||||
proto.use_new_networking = true;
|
||||
proto.enable_design_data_version_update = true;
|
||||
proto.enable_version_update = true;
|
||||
proto.mtp_switch = true;
|
||||
proto.forbid_recharge = true;
|
||||
proto.close_redeem_code = true;
|
||||
proto.ECBFEHFPOFJ = false;
|
||||
proto.enable_save_replay_file = true;
|
||||
proto.ios_exam = true;
|
||||
proto.event_tracking_open = true;
|
||||
proto.use_tcp = true;
|
||||
proto.enable_upload_battle_log = false;
|
||||
|
||||
const data = try proto.encode(res.arena);
|
||||
const size = Base64Encoder.calcSize(data.len);
|
||||
const output = try res.arena.alloc(u8, size);
|
||||
_ = Base64Encoder.encode(output, data);
|
||||
|
||||
res.body = output;
|
||||
}
|
||||
|
||||
pub fn selectHost(version: []const u8) []const u8 {
|
||||
if (std.mem.startsWith(u8, version, "CNPROD")) {
|
||||
return CNPROD_HOST;
|
||||
} else if (std.mem.startsWith(u8, version, "CNBETA")) {
|
||||
return CNBETA_HOST;
|
||||
} else if (std.mem.startsWith(u8, version, "OSPROD")) {
|
||||
return OSPROD_HOST;
|
||||
} else if (std.mem.startsWith(u8, version, "OSBETA")) {
|
||||
return OSBETA_HOST;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
pub fn constructUrl(host: []const u8, version: []const u8, dispatch_seed: []const u8) []const u8 {
|
||||
return std.fmt.allocPrint(std.heap.page_allocator, "https://{s}/query_gateway?version={s}&dispatch_seed={s}&language_type=1&platform_type=2&channel_id=1&sub_channel_id=1&is_need_url=1&account_type=1", .{ host, version, dispatch_seed }) catch "";
|
||||
}
|
95
dispatch/src/hotfix.zig
Normal file
95
dispatch/src/hotfix.zig
Normal file
|
@ -0,0 +1,95 @@
|
|||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const hotfixInfo = struct {
|
||||
clientVersion: []const u8,
|
||||
assetBundleUrl: []const u8,
|
||||
exResourceUrl: []const u8,
|
||||
luaUrl: []const u8,
|
||||
iFixUrl: []const u8,
|
||||
};
|
||||
|
||||
pub fn Parser(allocator: Allocator, filename: []const u8, version: []const u8) !hotfixInfo {
|
||||
const file = try std.fs.cwd().openFile(filename, .{});
|
||||
defer file.close();
|
||||
|
||||
const file_size = try file.getEndPos();
|
||||
const buffer = try file.readToEndAlloc(allocator, file_size);
|
||||
defer allocator.free(buffer);
|
||||
|
||||
var json_tree = try std.json.parseFromSlice(std.json.Value, allocator, buffer, .{ .ignore_unknown_fields = true });
|
||||
defer json_tree.deinit();
|
||||
|
||||
const version_node = json_tree.value.object.get(version) orelse {
|
||||
return hotfixInfo{
|
||||
.clientVersion = version,
|
||||
.assetBundleUrl = "",
|
||||
.exResourceUrl = "",
|
||||
.luaUrl = "",
|
||||
.iFixUrl = "",
|
||||
};
|
||||
};
|
||||
|
||||
return getValue(version_node, version);
|
||||
}
|
||||
|
||||
fn getValue(node: std.json.Value, client_version: []const u8) !hotfixInfo {
|
||||
if (node != .object) return error.InvalidJsonStructure;
|
||||
|
||||
const obj = node.object;
|
||||
|
||||
const assetBundleUrl = obj.get("asset_bundle_url") orelse return error.MissingAssetBundleUrl;
|
||||
const exResourceUrl = obj.get("ex_resource_url") orelse return error.MissingExResourceUrl;
|
||||
const luaUrl = obj.get("lua_url") orelse return error.MissingLuaUrl;
|
||||
const iFixUrl = obj.get("ifix_url") orelse return error.MissingIFixUrl;
|
||||
|
||||
if (assetBundleUrl != .string or
|
||||
exResourceUrl != .string or
|
||||
luaUrl != .string or
|
||||
iFixUrl != .string) return error.InvalidUrlFormat;
|
||||
|
||||
return hotfixInfo{
|
||||
.clientVersion = client_version,
|
||||
.assetBundleUrl = assetBundleUrl.string,
|
||||
.exResourceUrl = exResourceUrl.string,
|
||||
.luaUrl = luaUrl.string,
|
||||
.iFixUrl = iFixUrl.string,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn putValue(version: []const u8, assetBundleUrl: []const u8, exResourceUrl: []const u8, luaUrl: []const u8, iFixUrl: []const u8) !void {
|
||||
const file = try std.fs.cwd().openFile("hotfix.json", .{ .mode = .read_write });
|
||||
defer file.close();
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const allocator = arena.allocator();
|
||||
|
||||
const file_size = try file.getEndPos();
|
||||
const buffer0 = try file.readToEndAlloc(allocator, file_size);
|
||||
defer allocator.free(buffer0);
|
||||
|
||||
var json_tree = try std.json.parseFromSlice(std.json.Value, allocator, buffer0, .{ .ignore_unknown_fields = true });
|
||||
defer json_tree.deinit();
|
||||
|
||||
var root = json_tree.value.object;
|
||||
|
||||
var new_version = std.json.ObjectMap.init(allocator);
|
||||
try new_version.put("asset_bundle_url", .{ .string = assetBundleUrl });
|
||||
try new_version.put("ex_resource_url", .{ .string = exResourceUrl });
|
||||
try new_version.put("ifix_url", .{ .string = iFixUrl });
|
||||
try new_version.put("ifix_version", .{ .string = "0" });
|
||||
try new_version.put("lua_url", .{ .string = luaUrl });
|
||||
try new_version.put("lua_version", .{ .string = "" });
|
||||
try root.put(version, .{ .object = new_version });
|
||||
|
||||
const json_value = std.json.Value{ .object = root };
|
||||
|
||||
var buffer = std.ArrayList(u8).init(allocator);
|
||||
try std.json.stringify(json_value, .{ .whitespace = .indent_4 }, buffer.writer());
|
||||
|
||||
const new_file = try std.fs.cwd().createFile("hotfix.json", .{ .truncate = true });
|
||||
defer new_file.close();
|
||||
|
||||
try new_file.writeAll(buffer.items);
|
||||
}
|
35
dispatch/src/main.zig
Normal file
35
dispatch/src/main.zig
Normal file
|
@ -0,0 +1,35 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const httpz = @import("httpz");
|
||||
const protocol = @import("protocol");
|
||||
|
||||
const authentication = @import("authentication.zig");
|
||||
const dispatch = @import("dispatch.zig");
|
||||
const PORT = 21000;
|
||||
|
||||
pub const std_options = .{
|
||||
.log_level = switch (builtin.mode) {
|
||||
.Debug => .debug,
|
||||
else => .info,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var server = try httpz.Server().init(allocator, .{ .port = PORT });
|
||||
defer server.stop();
|
||||
defer server.deinit();
|
||||
var router = server.router();
|
||||
|
||||
router.get("/query_dispatch", dispatch.onQueryDispatch);
|
||||
router.get("/query_gateway", dispatch.onQueryGateway);
|
||||
router.post("/account/risky/api/check", authentication.onRiskyApiCheck);
|
||||
router.post("/:product_name/mdk/shield/api/login", authentication.onShieldLogin);
|
||||
router.post("/:product_name/mdk/shield/api/verify", authentication.onVerifyLogin);
|
||||
router.post("/:product_name/combo/granter/login/v2/login", authentication.onComboTokenReq);
|
||||
|
||||
std.log.info("Dispatch is listening at localhost:{?}", .{server.config.port});
|
||||
try server.listen();
|
||||
}
|
28
gameserver/build.zig
Normal file
28
gameserver/build.zig
Normal file
|
@ -0,0 +1,28 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const protocol = b.dependency("protocol", .{});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "gameserver",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
exe.root_module.addImport("protocol", protocol.module("protocol"));
|
||||
b.installArtifact(exe);
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
}
|
18
gameserver/build.zig.zon
Normal file
18
gameserver/build.zig.zon
Normal file
|
@ -0,0 +1,18 @@
|
|||
.{
|
||||
.name = "gameserver",
|
||||
.version = "0.0.0",
|
||||
.minimum_zig_version = "0.13.0",
|
||||
.dependencies = .{
|
||||
.protocol = .{
|
||||
.path = "../protocol",
|
||||
},
|
||||
},
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
// For example...
|
||||
//"LICENSE",
|
||||
//"README.md",
|
||||
},
|
||||
}
|
77
gameserver/src/Packet.zig
Normal file
77
gameserver/src/Packet.zig
Normal file
|
@ -0,0 +1,77 @@
|
|||
const std = @import("std");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Reader = std.net.Stream.Reader;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
cmd_id: u16,
|
||||
head: []u8,
|
||||
body: []u8,
|
||||
allocator: Allocator,
|
||||
|
||||
const head_magic: u32 = 0x9D74C714;
|
||||
const tail_magic: u32 = 0xD7A152C8;
|
||||
|
||||
pub const DecodeError = error{
|
||||
HeadMagicMismatch,
|
||||
TailMagicMismatch,
|
||||
PayloadTooBig,
|
||||
};
|
||||
|
||||
pub fn read(reader: *Reader, allocator: Allocator) !Self {
|
||||
if (try reader.readInt(u32, .big) != Self.head_magic) {
|
||||
return Self.DecodeError.HeadMagicMismatch;
|
||||
}
|
||||
|
||||
const cmd_id = try reader.readInt(u16, .big);
|
||||
const head_len = try reader.readInt(u16, .big);
|
||||
const body_len = try reader.readInt(u32, .big);
|
||||
|
||||
if (body_len > 0xFFFFFF) {
|
||||
return Self.DecodeError.PayloadTooBig;
|
||||
}
|
||||
|
||||
const head = try allocator.alloc(u8, head_len);
|
||||
errdefer allocator.free(head);
|
||||
|
||||
const body = try allocator.alloc(u8, body_len);
|
||||
errdefer allocator.free(body);
|
||||
|
||||
_ = try reader.readAll(head);
|
||||
_ = try reader.readAll(body);
|
||||
|
||||
if (try reader.readInt(u32, .big) != Self.tail_magic) {
|
||||
return Self.DecodeError.TailMagicMismatch;
|
||||
}
|
||||
|
||||
return .{
|
||||
.cmd_id = cmd_id,
|
||||
.head = head,
|
||||
.body = body,
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getProto(self: *const Self, comptime T: type, allocator: Allocator) !T {
|
||||
return try T.decode(self.body, allocator);
|
||||
}
|
||||
|
||||
pub fn encode(cmd_id: u16, head: []u8, body: []u8, allocator: Allocator) ![]u8 {
|
||||
var buf = try allocator.alloc(u8, 16 + head.len + body.len);
|
||||
|
||||
std.mem.writeInt(u32, buf[0..4], Self.head_magic, .big);
|
||||
std.mem.writeInt(u16, buf[4..6], cmd_id, .big);
|
||||
std.mem.writeInt(u16, buf[6..8], @intCast(head.len), .big);
|
||||
std.mem.writeInt(u32, buf[8..12], @intCast(body.len), .big);
|
||||
@memcpy(buf[12..(12 + head.len)], head);
|
||||
@memcpy(buf[(12 + head.len)..(12 + head.len + body.len)], body);
|
||||
std.mem.writeInt(u32, buf[(12 + head.len + body.len)..][0..4], Self.tail_magic, .big);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.allocator.free(self.head);
|
||||
self.allocator.free(self.body);
|
||||
}
|
55
gameserver/src/Session.zig
Normal file
55
gameserver/src/Session.zig
Normal file
|
@ -0,0 +1,55 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const handlers = @import("handlers.zig");
|
||||
const Packet = @import("Packet.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
|
||||
const Stream = std.net.Stream;
|
||||
const Address = std.net.Address;
|
||||
|
||||
const Self = @This();
|
||||
const log = std.log.scoped(.session);
|
||||
|
||||
address: Address,
|
||||
stream: Stream,
|
||||
allocator: Allocator,
|
||||
|
||||
pub fn init(address: Address, stream: Stream, allocator: Allocator) Self {
|
||||
return .{
|
||||
.address = address,
|
||||
.stream = stream,
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn run(self: *Self) !void {
|
||||
defer self.stream.close();
|
||||
|
||||
var reader = self.stream.reader();
|
||||
while (true) {
|
||||
var packet = Packet.read(&reader, self.allocator) catch break;
|
||||
defer packet.deinit();
|
||||
|
||||
try handlers.handle(self, &packet);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(self: *Self, cmd_id: protocol.CmdID, proto: anytype) !void {
|
||||
const data = try proto.encode(self.allocator);
|
||||
defer self.allocator.free(data);
|
||||
|
||||
const packet = try Packet.encode(@intFromEnum(cmd_id), &.{}, data, self.allocator);
|
||||
defer self.allocator.free(packet);
|
||||
|
||||
_ = try self.stream.write(packet);
|
||||
}
|
||||
|
||||
pub fn send_empty(self: *Self, cmd_id: protocol.CmdID) !void {
|
||||
const packet = try Packet.encode(@intFromEnum(cmd_id), &.{}, &.{}, self.allocator);
|
||||
defer self.allocator.free(packet);
|
||||
|
||||
_ = try self.stream.write(packet);
|
||||
log.debug("sent EMPTY packet with id {}", .{cmd_id});
|
||||
}
|
71
gameserver/src/command.zig
Normal file
71
gameserver/src/command.zig
Normal file
|
@ -0,0 +1,71 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("Session.zig");
|
||||
const Packet = @import("Packet.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
const value_command = @import("./commands/value.zig");
|
||||
const help_command = @import("./commands/help.zig");
|
||||
const tp_command = @import("./commands/tp.zig");
|
||||
const unstuck_command = @import("./commands/unstuck.zig");
|
||||
const sync_command = @import("./commands/sync.zig");
|
||||
const refill_command = @import("./commands/refill.zig");
|
||||
|
||||
// Add other errors if needed
|
||||
const SystemErrors = error{ CommandError, SystemResources, Unexpected, AccessDenied, WouldBlock, ConnectionResetByPeer, OutOfMemory, DiskQuota, FileTooBig, InputOutput, NoSpaceLeft, DeviceBusy, InvalidArgument, BrokenPipe, OperationAborted };
|
||||
const FileErrors = error{ NotOpenForWriting, LockViolation, Overflow, InvalidCharacter, ProcessFdQuotaExceeded, SystemFdQuotaExceeded, SymLinkLoop, NameTooLong, FileNotFound, NotDir, NoDevice, SharingViolation, PathAlreadyExists, PipeBusy, InvalidUtf8, InvalidWtf8, BadPathName, NetworkNotFound, AntivirusInterference, IsDir, FileLocksNotSupported, FileBusy };
|
||||
const NetworkErrors = error{ ConnectionTimedOut, NotOpenForReading, SocketNotConnected, Unseekable, StreamTooLong };
|
||||
const ParseErrors = error{ UnexpectedToken, InvalidNumber, InvalidEnumTag, DuplicateField, UnknownField, MissingField, LengthMismatch, SyntaxError, UnexpectedEndOfInput, BufferUnderrun, ValueTooLong, InsufficientTokens, InvalidFormat };
|
||||
const MiscErrors = error{ PermissionDenied, NetworkSubsystemFailed, FileSystem, CurrentWorkingDirectoryUnlinked, InvalidBatchScriptArg, InvalidExe, ResourceLimitReached, InvalidUserId, InvalidName, InvalidHandle, WaitAbandoned, WaitTimeOut, StdoutStreamTooLong, StderrStreamTooLong };
|
||||
pub const Error = SystemErrors || FileErrors || NetworkErrors || ParseErrors || MiscErrors;
|
||||
|
||||
const CommandFn = *const fn (session: *Session, args: []const u8, allocator: Allocator) Error!void;
|
||||
|
||||
const Command = struct {
|
||||
name: []const u8,
|
||||
action: []const u8,
|
||||
func: CommandFn,
|
||||
};
|
||||
|
||||
const commandList = [_]Command{
|
||||
Command{ .name = "help", .action = "", .func = help_command.handle },
|
||||
Command{ .name = "test", .action = "", .func = value_command.handle },
|
||||
Command{ .name = "node", .action = "", .func = value_command.challengeNode },
|
||||
Command{ .name = "set", .action = "", .func = value_command.setGachaCommand },
|
||||
Command{ .name = "tp", .action = "", .func = tp_command.handle },
|
||||
Command{ .name = "unstuck", .action = "", .func = unstuck_command.handle },
|
||||
Command{ .name = "sync", .action = "", .func = sync_command.onGenerateAndSync },
|
||||
Command{ .name = "refill", .action = "", .func = refill_command.onRefill },
|
||||
};
|
||||
|
||||
pub fn handleCommand(session: *Session, msg: []const u8, allocator: Allocator) Error!void {
|
||||
if (msg.len < 1 or msg[0] != '/') {
|
||||
std.debug.print("Message Text 2: {any}\n", .{msg});
|
||||
return sendMessage(session, "Commands must start with a '/'", allocator);
|
||||
}
|
||||
|
||||
const input = msg[1..]; // Remove the leading '/'
|
||||
var tokenizer = std.mem.tokenize(u8, input, " ");
|
||||
const command = tokenizer.next().?;
|
||||
const args = tokenizer.rest();
|
||||
|
||||
for (commandList) |cmd| {
|
||||
if (std.mem.eql(u8, cmd.name, command)) {
|
||||
return try cmd.func(session, args, allocator);
|
||||
}
|
||||
}
|
||||
try sendMessage(session, "Invalid command", allocator);
|
||||
}
|
||||
|
||||
pub fn sendMessage(session: *Session, msg: []const u8, allocator: Allocator) Error!void {
|
||||
var chat = protocol.RevcMsgScNotify.init(allocator);
|
||||
chat.message_type = protocol.MsgType.MSG_TYPE_CUSTOM_TEXT;
|
||||
chat.chat_type = protocol.ChatType.CHAT_TYPE_PRIVATE;
|
||||
chat.source_uid = 2000;
|
||||
chat.message_text = .{ .Const = msg };
|
||||
chat.target_uid = 1; // receiver_id
|
||||
try session.send(CmdID.CmdRevcMsgScNotify, chat);
|
||||
}
|
15
gameserver/src/commands/help.zig
Normal file
15
gameserver/src/commands/help.zig
Normal file
|
@ -0,0 +1,15 @@
|
|||
const commandhandler = @import("../command.zig");
|
||||
const std = @import("std");
|
||||
const Session = @import("../Session.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Error = commandhandler.Error;
|
||||
|
||||
pub fn handle(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
try commandhandler.sendMessage(session, "/tp to teleport, /sync to sync data from config\n", allocator);
|
||||
try commandhandler.sendMessage(session, "/refill to refill technique point after battle\n", allocator);
|
||||
try commandhandler.sendMessage(session, "/set to set gacha banner\n", allocator);
|
||||
try commandhandler.sendMessage(session, "/node to chage node in PF, AS, MoC\n", allocator);
|
||||
try commandhandler.sendMessage(session, "You can enter MoC, PF, AS via F4 menu\n", allocator);
|
||||
try commandhandler.sendMessage(session, "(If your Castorice technique enabled, you must enter battle by using Castorice's technique)\n", allocator);
|
||||
}
|
22
gameserver/src/commands/refill.zig
Normal file
22
gameserver/src/commands/refill.zig
Normal file
|
@ -0,0 +1,22 @@
|
|||
const commandhandler = @import("../command.zig");
|
||||
const std = @import("std");
|
||||
const Session = @import("../Session.zig");
|
||||
const protocol = @import("protocol");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("../services/config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const LineupManager = @import("../manager/lineup_mgr.zig").LineupManager;
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
const Error = commandhandler.Error;
|
||||
|
||||
pub fn onRefill(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
try commandhandler.sendMessage(session, "Refill skill point\n", allocator);
|
||||
var sync = protocol.SyncLineupNotify.init(allocator);
|
||||
var lineup_mgr = LineupManager.init(allocator);
|
||||
const lineup = try lineup_mgr.createLineup();
|
||||
sync.Lineup = lineup;
|
||||
try session.send(CmdID.CmdSyncLineupNotify, sync);
|
||||
}
|
288
gameserver/src/commands/sync.zig
Normal file
288
gameserver/src/commands/sync.zig
Normal file
|
@ -0,0 +1,288 @@
|
|||
const commandhandler = @import("../command.zig");
|
||||
const std = @import("std");
|
||||
const Session = @import("../Session.zig");
|
||||
const protocol = @import("protocol");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("../services/config.zig");
|
||||
const Item = @import("../services/item.zig");
|
||||
const Data = @import("../data.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
const Error = commandhandler.Error;
|
||||
|
||||
// function to check the list if true
|
||||
fn isInList(id: u32, list: []const u32) bool {
|
||||
for (list) |item| {
|
||||
if (item == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub var max_avatar_list: u32 = 0;
|
||||
|
||||
fn syncItems(session: *Session, allocator: Allocator, equip_avatar: bool) !void {
|
||||
resetGlobalUidGens();
|
||||
var sync = protocol.PlayerSyncScNotify.init(allocator);
|
||||
const config = try Config.loadGameConfig(allocator, "config.json");
|
||||
|
||||
for (config.avatar_config.items) |avatarConf| {
|
||||
const equip_avatar_id: u32 = if (equip_avatar) avatarConf.id else 0;
|
||||
const lc = protocol.Equipment{
|
||||
.unique_id = if (equip_avatar) nextGlobalId() else nextGlobalId(),
|
||||
.tid = avatarConf.lightcone.id,
|
||||
.is_protected = true,
|
||||
.level = avatarConf.lightcone.level,
|
||||
.rank = avatarConf.lightcone.rank,
|
||||
.promotion = avatarConf.lightcone.promotion,
|
||||
.equip_avatar_id = equip_avatar_id,
|
||||
};
|
||||
try sync.equipment_list.append(lc);
|
||||
|
||||
for (avatarConf.relics.items) |input| {
|
||||
var r = protocol.Relic{
|
||||
.tid = input.id,
|
||||
.main_affix_id = input.main_affix_id,
|
||||
.unique_id = if (equip_avatar) nextGlobalId() else nextGlobalId(),
|
||||
.exp = 0,
|
||||
.equip_avatar_id = equip_avatar_id,
|
||||
.is_protected = true,
|
||||
.level = input.level,
|
||||
.sub_affix_list = ArrayList(protocol.RelicAffix).init(allocator),
|
||||
.reforge_sub_affix_list = ArrayList(protocol.RelicAffix).init(allocator),
|
||||
};
|
||||
try r.sub_affix_list.append(protocol.RelicAffix{ .affix_id = input.stat1, .cnt = input.cnt1, .step = input.step1 });
|
||||
try r.sub_affix_list.append(protocol.RelicAffix{ .affix_id = input.stat2, .cnt = input.cnt2, .step = input.step2 });
|
||||
try r.sub_affix_list.append(protocol.RelicAffix{ .affix_id = input.stat3, .cnt = input.cnt3, .step = input.step3 });
|
||||
try r.sub_affix_list.append(protocol.RelicAffix{ .affix_id = input.stat4, .cnt = input.cnt4, .step = input.step4 });
|
||||
try sync.relic_list.append(r);
|
||||
}
|
||||
}
|
||||
try session.send(CmdID.CmdPlayerSyncScNotify, sync);
|
||||
}
|
||||
|
||||
pub fn onUndressEquipment(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
try syncItems(session, allocator, false);
|
||||
}
|
||||
pub fn onSyncEquipment(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
try syncItems(session, allocator, true);
|
||||
}
|
||||
|
||||
pub fn onSyncAvatar(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
resetGlobalUidGens();
|
||||
var sync = protocol.PlayerSyncScNotify.init(allocator);
|
||||
const config = try Config.loadGameConfig(allocator, "config.json");
|
||||
var char = protocol.AvatarSync.init(allocator);
|
||||
for (Data.AllAvatars) |id| {
|
||||
var avatar = protocol.Avatar.init(allocator);
|
||||
avatar.base_avatar_id = id;
|
||||
avatar.level = 80;
|
||||
avatar.promotion = 6;
|
||||
avatar.rank = 6;
|
||||
avatar.has_taken_promotion_reward_list = ArrayList(u32).init(allocator);
|
||||
for (1..6) |i| {
|
||||
try avatar.has_taken_promotion_reward_list.append(@intCast(i));
|
||||
}
|
||||
var talentLevel: u32 = 0;
|
||||
const skill_list: []const u32 = if (isInList(avatar.base_avatar_id, &Data.Rem)) &Data.skills else &Data.skills_old;
|
||||
for (skill_list) |elem| {
|
||||
talentLevel = switch (elem) {
|
||||
1 => 6,
|
||||
2...4 => 10,
|
||||
301, 302 => if (isInList(avatar.base_avatar_id, &Data.Rem)) 6 else 1,
|
||||
else => 1,
|
||||
};
|
||||
const talent = protocol.AvatarSkillTree{ .point_id = avatar.base_avatar_id * 1000 + elem, .level = talentLevel };
|
||||
try avatar.skilltree_list.append(talent);
|
||||
}
|
||||
try char.avatar_list.append(avatar);
|
||||
}
|
||||
// rewrite data of avatar in config
|
||||
for (config.avatar_config.items) |avatarConf| {
|
||||
var avatar = protocol.Avatar.init(allocator);
|
||||
// basic info
|
||||
avatar.base_avatar_id = switch (avatarConf.id) {
|
||||
8001...8008 => 8001,
|
||||
1224 => 1001,
|
||||
else => avatarConf.id,
|
||||
};
|
||||
avatar.level = avatarConf.level;
|
||||
avatar.promotion = avatarConf.promotion;
|
||||
avatar.rank = avatarConf.rank;
|
||||
if (isInList(avatar.base_avatar_id, &Data.EnhanceAvatarID)) avatar.NDEFNACPCLH = 1;
|
||||
avatar.has_taken_promotion_reward_list = ArrayList(u32).init(allocator);
|
||||
for (1..6) |i| {
|
||||
try avatar.has_taken_promotion_reward_list.append(@intCast(i));
|
||||
}
|
||||
avatar.equipment_unique_id = nextGlobalId();
|
||||
avatar.equip_relic_list = ArrayList(protocol.EquipRelic).init(allocator);
|
||||
for (0..6) |i| {
|
||||
try avatar.equip_relic_list.append(.{
|
||||
.relic_unique_id = nextGlobalId(), // uid
|
||||
.type = @intCast(i), // slot
|
||||
});
|
||||
}
|
||||
var talentLevel: u32 = 0;
|
||||
const skill_list: []const u32 = if (isInList(avatar.base_avatar_id, &Data.Rem)) &Data.skills else &Data.skills_old;
|
||||
for (skill_list) |elem| {
|
||||
talentLevel = switch (elem) {
|
||||
1 => 6,
|
||||
2...4 => 10,
|
||||
301, 302 => if (isInList(avatar.base_avatar_id, &Data.Rem)) 6 else 1,
|
||||
else => 1,
|
||||
};
|
||||
var point_id: u32 = 0;
|
||||
if (isInList(avatar.base_avatar_id, &Data.EnhanceAvatarID)) point_id = avatar.base_avatar_id + 10000 else point_id = avatar.base_avatar_id;
|
||||
const talent = protocol.AvatarSkillTree{ .point_id = point_id * 1000 + elem, .level = talentLevel };
|
||||
try avatar.skilltree_list.append(talent);
|
||||
}
|
||||
try char.avatar_list.append(avatar);
|
||||
const avatarType: protocol.MultiPathAvatarType = @enumFromInt(avatarConf.id);
|
||||
if (@intFromEnum(avatarType) > 1) {
|
||||
try session.send(CmdID.CmdSetAvatarPathScRsp, protocol.SetAvatarPathScRsp{
|
||||
.retcode = 0,
|
||||
.avatar_id = avatarType,
|
||||
});
|
||||
}
|
||||
}
|
||||
max_avatar_list = @intCast(config.avatar_config.items.len);
|
||||
sync.avatar_sync = char;
|
||||
try session.send(CmdID.CmdPlayerSyncScNotify, sync);
|
||||
}
|
||||
// TODO: DO WITH MALE MC TOO :Đ
|
||||
pub fn onSyncMultiPath(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
var sync = protocol.PlayerSyncScNotify.init(allocator);
|
||||
const config = try Config.loadGameConfig(allocator, "config.json");
|
||||
const currentAvatarId = getCurrentGlobalId();
|
||||
const GeneratorType = UidGen();
|
||||
const avatar_ids = [_][]const u32{
|
||||
&[_]u32{ 8001, 8002 },
|
||||
&[_]u32{ 8003, 8004 },
|
||||
&[_]u32{ 8005, 8006 },
|
||||
&[_]u32{ 8007, 8008 },
|
||||
&[_]u32{1001},
|
||||
&[_]u32{1224},
|
||||
};
|
||||
const avatar_types = [_]protocol.MultiPathAvatarType{
|
||||
.GirlWarriorType, .GirlKnightType, .GirlShamanType,
|
||||
.GirlMemoryType, .Mar_7thKnightType, .Mar_7thRogueType,
|
||||
};
|
||||
var indexes: [6]u32 = [_]u32{0} ** 6;
|
||||
var counts: [6]u32 = [_]u32{0} ** 6;
|
||||
var multis: [6]protocol.MultiPathAvatarInfo = undefined;
|
||||
for (&multis, avatar_types, 0..) |*multi, avatar_type, i| {
|
||||
std.debug.print("MULTIPATH AVATAR INDEX: {} IS {}\n", .{ i, avatar_type });
|
||||
multi.* = protocol.MultiPathAvatarInfo.init(allocator);
|
||||
multi.avatar_id = avatar_type;
|
||||
if (avatar_type == .Mar_7thKnightType) {
|
||||
multi.dressed_skin_id = 1100101;
|
||||
}
|
||||
}
|
||||
for (config.avatar_config.items) |avatar| {
|
||||
for (0..avatar_ids.len) |i| {
|
||||
counts[i] += 1;
|
||||
for (avatar_ids[i]) |id| {
|
||||
if (avatar.id == id) {
|
||||
multis[i].rank = avatar.rank;
|
||||
indexes[i] = max_avatar_list + 1 - counts[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var generators: [6]GeneratorType = undefined;
|
||||
for (0..multis.len) |i| {
|
||||
generators[i] = GeneratorType.init(currentAvatarId - (indexes[i] * 7) + 1);
|
||||
}
|
||||
for (0..multis.len) |i| {
|
||||
var multi = &multis[i];
|
||||
var gen = &generators[i];
|
||||
|
||||
multi.path_equipment_id = currentAvatarId - (indexes[i] * 7) + 1;
|
||||
multi.equip_relic_list = ArrayList(protocol.EquipRelic).init(allocator);
|
||||
|
||||
for (0..6) |slot| {
|
||||
try multi.equip_relic_list.append(.{
|
||||
.relic_unique_id = gen.nextId(),
|
||||
.type = @intCast(slot),
|
||||
});
|
||||
}
|
||||
}
|
||||
for (0..multis.len) |i| {
|
||||
const skill_set = if (i == 3) &Data.skills else &Data.skills_old;
|
||||
for (skill_set) |skill| {
|
||||
const talent_level: u32 = if (skill == 1 or skill == 301 or skill == 302) 6 else if (skill <= 4) 10 else 1;
|
||||
const point_id = if (avatar_ids[i].len > 1)
|
||||
avatar_ids[i][1] * 1000 + skill
|
||||
else
|
||||
avatar_ids[i][0] * 1000 + skill;
|
||||
const talent = protocol.AvatarSkillTree{
|
||||
.point_id = point_id,
|
||||
.level = talent_level,
|
||||
};
|
||||
try multis[i].multi_path_skill_tree.append(talent);
|
||||
}
|
||||
}
|
||||
try sync.multi_path_avatar_info_list.appendSlice(&multis);
|
||||
try session.send(CmdID.CmdPlayerSyncScNotify, sync);
|
||||
}
|
||||
|
||||
pub var global_uid_gen: UidGenerator = undefined;
|
||||
|
||||
fn resetGlobalUidGens() void {
|
||||
global_uid_gen = UidGenerator.init(0);
|
||||
}
|
||||
|
||||
pub fn nextGlobalId() u32 {
|
||||
return global_uid_gen.nextId();
|
||||
}
|
||||
|
||||
pub fn getCurrentGlobalId() u32 {
|
||||
return global_uid_gen.getCurrentId();
|
||||
}
|
||||
|
||||
pub const UidGenerator = struct {
|
||||
current_id: u32,
|
||||
|
||||
pub fn init(start_id: u32) UidGenerator {
|
||||
return UidGenerator{ .current_id = start_id };
|
||||
}
|
||||
|
||||
pub fn nextId(self: *UidGenerator) u32 {
|
||||
self.current_id += 1;
|
||||
return self.current_id;
|
||||
}
|
||||
|
||||
pub fn getCurrentId(self: *const UidGenerator) u32 {
|
||||
return self.current_id;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn UidGen() type {
|
||||
return struct {
|
||||
current_id: u32,
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(start_id: u32) Self {
|
||||
return Self{ .current_id = start_id };
|
||||
}
|
||||
|
||||
pub fn nextId(self: *Self) u32 {
|
||||
self.current_id += 1;
|
||||
return self.current_id;
|
||||
}
|
||||
|
||||
pub fn getCurrentId(self: *const Self) u32 {
|
||||
return self.current_id;
|
||||
}
|
||||
};
|
||||
}
|
||||
pub fn onGenerateAndSync(session: *Session, placeholder: []const u8, allocator: Allocator) Error!void {
|
||||
try commandhandler.sendMessage(session, "Sync items with config\n", allocator);
|
||||
try syncItems(session, allocator, false);
|
||||
try syncItems(session, allocator, true);
|
||||
try onSyncAvatar(session, placeholder, allocator);
|
||||
try onSyncMultiPath(session, placeholder, allocator);
|
||||
}
|
61
gameserver/src/commands/tp.zig
Normal file
61
gameserver/src/commands/tp.zig
Normal file
|
@ -0,0 +1,61 @@
|
|||
const commandhandler = @import("../command.zig");
|
||||
const std = @import("std");
|
||||
const Session = @import("../Session.zig");
|
||||
const protocol = @import("protocol");
|
||||
const Config = @import("../services/config.zig");
|
||||
const Res_config = @import("../services/res_config.zig");
|
||||
const LineupManager = @import("../manager/lineup_mgr.zig").LineupManager;
|
||||
const SceneManager = @import("../manager/scene_mgr.zig").SceneManager;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
const Error = commandhandler.Error;
|
||||
|
||||
pub fn handle(session: *Session, args: []const u8, allocator: Allocator) Error!void {
|
||||
var arg_iter = std.mem.split(u8, args, " ");
|
||||
const entry_id_str = arg_iter.next() orelse {
|
||||
try commandhandler.sendMessage(session, "Error: Missing arguments.\nUsage: /tp <entry_id> [plane_id] [floor_id]", allocator);
|
||||
return;
|
||||
};
|
||||
const entry_id = std.fmt.parseInt(u32, entry_id_str, 10) catch {
|
||||
try commandhandler.sendMessage(session, "Error: Invalid entry ID. Please provide a valid unsigned 32-bit integer.", allocator);
|
||||
return;
|
||||
};
|
||||
var plane_id: ?u32 = null;
|
||||
if (arg_iter.next()) |plane_id_str| {
|
||||
plane_id = std.fmt.parseInt(u32, plane_id_str, 10) catch {
|
||||
try commandhandler.sendMessage(session, "Error: Invalid plane ID. Please provide a valid unsigned 32-bit integer.", allocator);
|
||||
return;
|
||||
};
|
||||
}
|
||||
var floor_id: ?u32 = null;
|
||||
if (arg_iter.next()) |floor_id_str| {
|
||||
floor_id = std.fmt.parseInt(u32, floor_id_str, 10) catch {
|
||||
try commandhandler.sendMessage(session, "Error: Invalid floor ID. Please provide a valid unsigned 32-bit integer.", allocator);
|
||||
return;
|
||||
};
|
||||
}
|
||||
var tp_msg = try std.fmt.allocPrint(allocator, "Teleporting to entry ID: {d}", .{entry_id});
|
||||
if (plane_id) |pid| {
|
||||
tp_msg = try std.fmt.allocPrint(allocator, "{s}, plane ID: {d}", .{ tp_msg, pid });
|
||||
}
|
||||
if (floor_id) |fid| {
|
||||
tp_msg = try std.fmt.allocPrint(allocator, "{s}, floor ID: {d}", .{ tp_msg, fid });
|
||||
}
|
||||
|
||||
try commandhandler.sendMessage(session, std.fmt.allocPrint(allocator, "Teleporting to entry ID: {d} {any} {any}\n", .{ entry_id, plane_id, floor_id }) catch "Error formatting message", allocator);
|
||||
|
||||
var planeID: u32 = 0;
|
||||
var floorID: u32 = 0;
|
||||
if (plane_id) |pid| planeID = pid;
|
||||
if (floor_id) |fid| floorID = fid;
|
||||
var scene_manager = SceneManager.init(allocator);
|
||||
const scene_info = try scene_manager.createScene(planeID, floorID, entry_id, 0);
|
||||
var lineup_mgr = LineupManager.init(allocator);
|
||||
const lineup = try lineup_mgr.createLineup();
|
||||
try session.send(CmdID.CmdEnterSceneByServerScNotify, protocol.EnterSceneByServerScNotify{
|
||||
.reason = protocol.EnterSceneReason.ENTER_SCENE_REASON_NONE,
|
||||
.lineup = lineup,
|
||||
.scene = scene_info,
|
||||
});
|
||||
}
|
23
gameserver/src/commands/unstuck.zig
Normal file
23
gameserver/src/commands/unstuck.zig
Normal file
|
@ -0,0 +1,23 @@
|
|||
const commandhandler = @import("../command.zig");
|
||||
const std = @import("std");
|
||||
const Session = @import("../Session.zig");
|
||||
const protocol = @import("protocol");
|
||||
const LineupManager = @import("../manager/lineup_mgr.zig").LineupManager;
|
||||
const SceneManager = @import("../manager/scene_mgr.zig").SceneManager;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
const Error = commandhandler.Error;
|
||||
|
||||
pub fn handle(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
var lineup_mgr = LineupManager.init(allocator);
|
||||
const lineup = try lineup_mgr.createLineup();
|
||||
var scene_manager = SceneManager.init(allocator);
|
||||
const scene_info = try scene_manager.createScene(20421, 20421001, 2042101, 2042106);
|
||||
|
||||
try session.send(CmdID.CmdEnterSceneByServerScNotify, protocol.EnterSceneByServerScNotify{
|
||||
.reason = protocol.EnterSceneReason.ENTER_SCENE_REASON_DIMENSION_MERGE,
|
||||
.lineup = lineup,
|
||||
.scene = scene_info,
|
||||
});
|
||||
}
|
124
gameserver/src/commands/value.zig
Normal file
124
gameserver/src/commands/value.zig
Normal file
|
@ -0,0 +1,124 @@
|
|||
const commandhandler = @import("../command.zig");
|
||||
const std = @import("std");
|
||||
const Session = @import("../Session.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Error = commandhandler.Error;
|
||||
|
||||
pub var challenge_node: u32 = 0;
|
||||
pub var StandardBanner = [_]u32{ 1003, 1004, 1101, 1104, 1209, 1211 };
|
||||
pub var RateUp = [_]u32{1406};
|
||||
pub var RateUpFourStars = [_]u32{ 1210, 1108, 1207 };
|
||||
|
||||
pub fn handle(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
try commandhandler.sendMessage(session, "Test Command for Chat\n", allocator);
|
||||
}
|
||||
pub fn challengeNode(session: *Session, _: []const u8, allocator: Allocator) Error!void {
|
||||
if (challenge_node == 0) {
|
||||
try commandhandler.sendMessage(session, "Change Challenge Node 2 \n", allocator);
|
||||
challenge_node = challenge_node + 1;
|
||||
} else {
|
||||
try commandhandler.sendMessage(session, "Change Challenge Node 1 \n", allocator);
|
||||
challenge_node = challenge_node - 1;
|
||||
}
|
||||
}
|
||||
pub fn setGachaCommand(session: *Session, args: []const u8, allocator: Allocator) Error!void {
|
||||
var arg_iter = std.mem.split(u8, args, " ");
|
||||
const command = arg_iter.next() orelse {
|
||||
try commandhandler.sendMessage(session, "Error: Missing sub-command. Usage: /set <sub-command> [arguments]", allocator);
|
||||
return;
|
||||
};
|
||||
if (std.mem.eql(u8, command, "standard")) {
|
||||
try standard(session, &arg_iter, allocator);
|
||||
} else if (std.mem.eql(u8, command, "rateup")) {
|
||||
const next = arg_iter.next();
|
||||
if (next) |rateup_number| {
|
||||
if (std.mem.eql(u8, rateup_number, "5")) {
|
||||
try gacha5Stars(session, &arg_iter, allocator);
|
||||
} else if (std.mem.eql(u8, rateup_number, "4")) {
|
||||
try gacha4Stars(session, &arg_iter, allocator);
|
||||
} else {
|
||||
try commandhandler.sendMessage(session, "Error: Invalid rateup number. Please use 4 (four stars) or 5 (5 stars).", allocator);
|
||||
}
|
||||
} else {
|
||||
try commandhandler.sendMessage(session, "Error: Missing number for rateup. Usage: /set rateup <number>", allocator);
|
||||
}
|
||||
} else {
|
||||
try commandhandler.sendMessage(session, "Error: Unknown sub-command. Available: standard, rateup 5, rateup 4", allocator);
|
||||
}
|
||||
}
|
||||
|
||||
fn standard(session: *Session, arg_iter: *std.mem.SplitIterator(u8, .sequence), allocator: Allocator) Error!void {
|
||||
var avatar_ids: [6]u32 = undefined;
|
||||
var count: usize = 0;
|
||||
while (count < 6) {
|
||||
if (arg_iter.next()) |avatar_id_str| {
|
||||
const id = std.fmt.parseInt(u32, avatar_id_str, 10) catch {
|
||||
return sendErrorMessage(session, "Error: Invalid avatar ID. Please provide a valid unsigned 32-bit integer.", allocator);
|
||||
};
|
||||
if (!isValidAvatarId(id)) {
|
||||
return sendErrorMessage(session, "Error: Invalid Avatar ID format.", allocator);
|
||||
}
|
||||
avatar_ids[count] = id;
|
||||
count += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (arg_iter.next() != null or count != 6) {
|
||||
return sendErrorMessage(session, "Error: You must provide exactly 6 avatar IDs.", allocator);
|
||||
}
|
||||
@memcpy(&StandardBanner, &avatar_ids);
|
||||
const msg = try std.fmt.allocPrint(allocator, "Set standard banner ID to: {d}, {d}, {d}, {d}, {d}, {d}", .{ avatar_ids[0], avatar_ids[1], avatar_ids[2], avatar_ids[3], avatar_ids[4], avatar_ids[5] });
|
||||
try commandhandler.sendMessage(session, msg, allocator);
|
||||
}
|
||||
fn gacha4Stars(session: *Session, arg_iter: *std.mem.SplitIterator(u8, .sequence), allocator: Allocator) Error!void {
|
||||
var avatar_ids: [3]u32 = undefined;
|
||||
var count: usize = 0;
|
||||
while (count < 3) {
|
||||
if (arg_iter.next()) |avatar_id_str| {
|
||||
const id = std.fmt.parseInt(u32, avatar_id_str, 10) catch {
|
||||
return sendErrorMessage(session, "Error: Invalid avatar ID. Please provide a valid unsigned 32-bit integer.", allocator);
|
||||
};
|
||||
if (!isValidAvatarId(id)) {
|
||||
return sendErrorMessage(session, "Error: Invalid Avatar ID format.", allocator);
|
||||
}
|
||||
avatar_ids[count] = id;
|
||||
count += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (arg_iter.next() != null or count != 3) {
|
||||
return sendErrorMessage(session, "Error: You must provide exactly 3 avatar IDs.", allocator);
|
||||
}
|
||||
@memcpy(&RateUpFourStars, &avatar_ids);
|
||||
const msg = try std.fmt.allocPrint(allocator, "Set 4 star rate up ID to: {d}, {d}, {d}", .{ avatar_ids[0], avatar_ids[1], avatar_ids[2] });
|
||||
try commandhandler.sendMessage(session, msg, allocator);
|
||||
}
|
||||
fn gacha5Stars(session: *Session, arg_iter: *std.mem.SplitIterator(u8, .sequence), allocator: Allocator) Error!void {
|
||||
var avatar_ids: [1]u32 = undefined;
|
||||
if (arg_iter.next()) |avatar_id_str| {
|
||||
const id = std.fmt.parseInt(u32, avatar_id_str, 10) catch {
|
||||
return sendErrorMessage(session, "Error: Invalid avatar ID. Please provide a valid unsigned 32-bit integer.", allocator);
|
||||
};
|
||||
if (!isValidAvatarId(id)) {
|
||||
return sendErrorMessage(session, "Error: Invalid Avatar ID format.", allocator);
|
||||
}
|
||||
avatar_ids[0] = id;
|
||||
} else {
|
||||
return sendErrorMessage(session, "Error: You must provide a rate-up avatar ID.", allocator);
|
||||
}
|
||||
if (arg_iter.next() != null) {
|
||||
return sendErrorMessage(session, "Error: Only one rate-up avatar ID is allowed.", allocator);
|
||||
}
|
||||
@memcpy(&RateUp, &avatar_ids);
|
||||
const msg = try std.fmt.allocPrint(allocator, "Set rate up ID to: {d}", .{avatar_ids[0]});
|
||||
try commandhandler.sendMessage(session, msg, allocator);
|
||||
}
|
||||
fn sendErrorMessage(session: *Session, message: []const u8, allocator: Allocator) Error!void {
|
||||
try commandhandler.sendMessage(session, message, allocator);
|
||||
}
|
||||
fn isValidAvatarId(avatar_id: u32) bool {
|
||||
return avatar_id >= 1000 and avatar_id <= 9999;
|
||||
}
|
77
gameserver/src/data.zig
Normal file
77
gameserver/src/data.zig
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Avatar group
|
||||
pub const MultiAvatar = [_]u32{
|
||||
8002, 8004, 8006, 8008, 1001, 1224,
|
||||
};
|
||||
pub const McTracing = [_]u32{
|
||||
8002, 8004, 8006, 8008,
|
||||
};
|
||||
pub const EnhanceAvatarID = [_]u32{ 1005, 1006, 1205, 1212 };
|
||||
|
||||
pub const skills = [_]u32{ 1, 2, 3, 4, 7, 101, 102, 103, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 301, 302 };
|
||||
pub const skills_old = [_]u32{ 1, 2, 3, 4, 7, 101, 102, 103, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210 };
|
||||
|
||||
pub const AllAvatars = &[_]u32{
|
||||
//1000
|
||||
1001, 1002, 1003, 1004, 1005, 1006, 1008, 1009, 1013, 1014, 1015,
|
||||
//1100
|
||||
1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
|
||||
1112,
|
||||
//1200
|
||||
1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210,
|
||||
1211, 1212, 1213, 1214, 1215, 1217, 1218, 1220, 1221, 1222, 1223,
|
||||
1225,
|
||||
//1300
|
||||
1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310,
|
||||
1312, 1313, 1314, 1315, 1317,
|
||||
//1400
|
||||
1401, 1402, 8001, 1403, 1404, 1405,
|
||||
1406, 1407, 1408, 1409,
|
||||
};
|
||||
// Battle group
|
||||
//TODO: update every patch
|
||||
pub const buffs_unlocked = &[_]u32{
|
||||
100101, 100201, 100301, 100401, 100501, 100601, 100801, 100901, 101301,
|
||||
110101, 110201, 110202, 110203, 110301, 110401, 110501, 110601, 110701,
|
||||
110801, 110901, 111001, 111101, 111201, 120101, 120301, 120401, 120501,
|
||||
120601, 120701, 120702, 120801, 120802, 120901, 121001, 121101, 121201,
|
||||
121202, 121203, 121301, 121302, 121303, 121401, 121501, 121701, 121801,
|
||||
122001, 122002, 122003, 122004, 122101, 122201, 122301, 122302, 122303,
|
||||
122304, 122402, 122403, 122501, 130101, 130201, 130301, 130302, 130303,
|
||||
130401, 130402, 130403, 130404, 130405, 130406, 130501, 130601, 130602,
|
||||
130701, 130801, 130802, 130803, 130901, 130902, 130903, 131001, 131002,
|
||||
131201, 131301, 131401, 131501, 131502, 131503, 131701, 131702, 140101,
|
||||
140102, 140201, 140202, 140301, 140401, 140501, 140601, 140701, 140801,
|
||||
140901, 200501, 200601, 220501, 221201, 800301, 800501, 101401, 101501,
|
||||
};
|
||||
|
||||
//TODO: update more Remembrance character in future
|
||||
pub const Rem = [_]u32{ 8007, 8008, 1402, 1407, 1409 };
|
||||
|
||||
//TODO: update id for characters have ignore toughness in their technique in future
|
||||
pub const IgnoreToughness = [_]u32{ 1006, 1308, 1317 };
|
||||
|
||||
// Profile group
|
||||
pub const OwnedChatBubbles = [_]u32{ 220000, 220001, 220002, 220003, 220004, 220005, 220006, 220007, 220008 };
|
||||
pub const OwnedPhoneThemes = [_]u32{ 221000, 221001, 221002, 221003, 221004, 221005, 221006, 221007, 221008, 221009, 221010, 221011 };
|
||||
pub const OwnedPhoneCases = [_]u32{ 254000, 254001 };
|
||||
|
||||
pub const OwnedPersonalCardSkin = [_]u32{253000};
|
||||
|
||||
pub const ItemList = [_]u32{ 251001, 251002, 110431, 110507, 101 };
|
||||
|
||||
pub const LightconeList_3 = [_]u32{
|
||||
20000, 20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20009, 20010, 20011, 20012, 20013, 20014, 20015, 20016, 20017, 20018, 20019, 20020, 20021, 20022,
|
||||
};
|
||||
pub const LightconeList_4 = [_]u32{
|
||||
21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21009, 21010, 21011, 21012, 21013, 21014, 21015, 21016, 21017, 21018, 21019, 21020, 21021, 21022,
|
||||
21023, 21024, 21025, 21026, 21027, 21028, 21029, 21030, 21031, 21032, 21033, 21034, 21035, 21036, 21037, 21038, 21039, 21040, 21041, 21042, 21043, 21044, 21045,
|
||||
21046, 21047, 21048, 21050, 21051, 21052, 22000, 22001, 22002, 22003, 22004,
|
||||
};
|
||||
pub const LightconeList_5 = [_]u32{
|
||||
23000, 23001, 23002, 23003, 23004, 23005, 23006, 23007, 23008, 23009, 23010, 23011, 23012, 23013, 23014, 23015, 23016, 23017, 23018, 23019, 23020, 23021, 23022,
|
||||
23023, 23024, 23025, 23026, 23027, 23028, 23029, 23030, 23031, 23032, 23033, 23034, 23035, 23036, 23037, 23038, 23039, 23040, 23041, 23042, 23043, 24000, 24001,
|
||||
24002, 24003, 24004, 24005,
|
||||
};
|
||||
pub const AvatarList = [_]u32{
|
||||
1001, 1002, 1008, 1009, 1013, 1103, 1105, 1106, 1108, 1109, 1110, 1111, 1201, 1202, 1206, 1207, 1210, 1214, 1215, 1223, 1224, 1301, 1312,
|
||||
};
|
251
gameserver/src/handlers.zig
Normal file
251
gameserver/src/handlers.zig
Normal file
|
@ -0,0 +1,251 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("Session.zig");
|
||||
const Packet = @import("Packet.zig");
|
||||
const avatar = @import("services/avatar.zig");
|
||||
const chat = @import("services/chat.zig");
|
||||
const gacha = @import("services/gacha.zig");
|
||||
const item = @import("services/item.zig");
|
||||
const battle = @import("services/battle.zig");
|
||||
const login = @import("services/login.zig");
|
||||
const lineup = @import("services/lineup.zig");
|
||||
const mail = @import("services/mail.zig");
|
||||
const misc = @import("services/misc.zig");
|
||||
const mission = @import("services/mission.zig");
|
||||
const pet = @import("services/pet.zig");
|
||||
const profile = @import("services/profile.zig");
|
||||
const scene = @import("services/scene.zig");
|
||||
const events = @import("services/events.zig");
|
||||
const challenge = @import("services/challenge.zig");
|
||||
const multipath = @import("services/multipath.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
const log = std.log.scoped(.handlers);
|
||||
|
||||
const Action = *const fn (*Session, *const Packet, Allocator) anyerror!void;
|
||||
const HandlerList = [_]struct { CmdID, Action }{
|
||||
.{ CmdID.CmdPlayerGetTokenCsReq, login.onPlayerGetToken },
|
||||
.{ CmdID.CmdPlayerLoginCsReq, login.onPlayerLogin },
|
||||
.{ CmdID.CmdPlayerHeartBeatCsReq, misc.onPlayerHeartBeat },
|
||||
.{ CmdID.CmdPlayerLoginFinishCsReq, login.onPlayerLoginFinish },
|
||||
.{ CmdID.CmdContentPackageGetDataCsReq, login.onContentPackageGetData },
|
||||
.{ CmdID.CmdSetClientPausedCsReq, login.onSetClientPaused },
|
||||
//avatar
|
||||
.{ CmdID.CmdGetAvatarDataCsReq, avatar.onGetAvatarData },
|
||||
.{ CmdID.CmdSetAvatarPathCsReq, avatar.onSetAvatarPath },
|
||||
.{ CmdID.CmdGetBasicInfoCsReq, avatar.onGetBasicInfo },
|
||||
.{ CmdID.CmdTakeOffAvatarSkinCsReq, avatar.onTakeOffAvatarSkin },
|
||||
.{ CmdID.CmdDressAvatarSkinCsReq, avatar.onDressAvatarSkin },
|
||||
.{ CmdID.CmdGetBigDataAllRecommendCsReq, avatar.onGetBigDataAll },
|
||||
.{ CmdID.CmdGetBigDataRecommendCsReq, avatar.onGetBigData },
|
||||
.{ CmdID.CmdGetPreAvatarGrowthInfoCsReq, avatar.onGetPreAvatarGrowthInfo },
|
||||
//bag
|
||||
.{ CmdID.CmdGetBagCsReq, item.onGetBag },
|
||||
.{ CmdID.CmdUseItemCsReq, item.onUseItem },
|
||||
//lineup
|
||||
.{ CmdID.CmdChangeLineupLeaderCsReq, lineup.onChangeLineupLeader },
|
||||
.{ CmdID.CmdReplaceLineupCsReq, lineup.onReplaceLineup },
|
||||
.{ CmdID.CmdGetCurLineupDataCsReq, lineup.onGetCurLineupData },
|
||||
//battle
|
||||
.{ CmdID.CmdStartCocoonStageCsReq, battle.onStartCocoonStage },
|
||||
.{ CmdID.CmdPVEBattleResultCsReq, battle.onPVEBattleResult },
|
||||
.{ CmdID.CmdSceneCastSkillCsReq, battle.onSceneCastSkill },
|
||||
.{ CmdID.CmdSceneCastSkillCostMpCsReq, battle.onSceneCastSkillCostMp },
|
||||
.{ CmdID.CmdQuickStartCocoonStageCsReq, battle.onQuickStartCocoonStage },
|
||||
.{ CmdID.CmdQuickStartFarmElementCsReq, battle.onQuickStartFarmElement },
|
||||
.{ CmdID.CmdStartBattleCollegeCsReq, battle.onStartBattleCollege },
|
||||
.{ CmdID.CmdGetCurBattleInfoCsReq, battle.onGetCurBattleInfo },
|
||||
.{ CmdID.CmdSyncClientResVersionCsReq, battle.onSyncClientResVersion },
|
||||
//gacha
|
||||
.{ CmdID.CmdGetGachaInfoCsReq, gacha.onGetGachaInfo },
|
||||
.{ CmdID.CmdBuyGoodsCsReq, gacha.onBuyGoods },
|
||||
.{ CmdID.CmdGetShopListCsReq, gacha.onGetShopList },
|
||||
.{ CmdID.CmdExchangeHcoinCsReq, gacha.onExchangeHcoin },
|
||||
.{ CmdID.CmdDoGachaCsReq, gacha.onDoGacha },
|
||||
//mail
|
||||
.{ CmdID.CmdGetMailCsReq, mail.onGetMail },
|
||||
//pet
|
||||
.{ CmdID.CmdGetPetDataCsReq, pet.onGetPetData },
|
||||
.{ CmdID.CmdRecallPetCsReq, pet.onRecallPet },
|
||||
.{ CmdID.CmdSummonPetCsReq, pet.onSummonPet },
|
||||
//profile
|
||||
.{ CmdID.CmdGetPhoneDataCsReq, profile.onGetPhoneData },
|
||||
.{ CmdID.CmdSelectPhoneThemeCsReq, profile.onSelectPhoneTheme },
|
||||
.{ CmdID.CmdSelectChatBubbleCsReq, profile.onSelectChatBubble },
|
||||
.{ CmdID.CmdGetPlayerBoardDataCsReq, profile.onGetPlayerBoardData },
|
||||
.{ CmdID.CmdSetDisplayAvatarCsReq, profile.onSetDisplayAvatar },
|
||||
.{ CmdID.CmdSetAssistAvatarCsReq, profile.onSetAssistAvatar },
|
||||
.{ CmdID.CmdSetSignatureCsReq, profile.onSetSignature },
|
||||
.{ CmdID.CmdSetGameplayBirthdayCsReq, profile.onSetGameplayBirthday },
|
||||
.{ CmdID.CmdSetHeadIconCsReq, profile.onSetHeadIcon },
|
||||
.{ CmdID.CmdSelectPhoneCaseCsReq, profile.onSelectPhoneCase },
|
||||
//mission
|
||||
.{ CmdID.CmdGetTutorialGuideCsReq, mission.onGetTutorialGuideStatus },
|
||||
.{ CmdID.CmdGetMissionStatusCsReq, mission.onGetMissionStatus },
|
||||
.{ CmdID.CmdGetTutorialCsReq, mission.onGetTutorialStatus },
|
||||
.{ CmdID.CmdUnlockTutorialGuideCsReq, mission.onUnlockTutorialGuide },
|
||||
.{ CmdID.CmdUnlockTutorialCsReq, mission.onUnlockTutorial },
|
||||
//chat
|
||||
.{ CmdID.CmdGetFriendListInfoCsReq, chat.onGetFriendListInfo },
|
||||
.{ CmdID.CmdGetPrivateChatHistoryCsReq, chat.onPrivateChatHistory },
|
||||
.{ CmdID.CmdGetChatEmojiListCsReq, chat.onChatEmojiList },
|
||||
.{ CmdID.CmdSendMsgCsReq, chat.onSendMsg },
|
||||
//scene
|
||||
.{ CmdID.CmdGetCurSceneInfoCsReq, scene.onGetCurSceneInfo },
|
||||
.{ CmdID.CmdSceneEntityMoveCsReq, scene.onSceneEntityMove },
|
||||
.{ CmdID.CmdEnterSceneCsReq, scene.onEnterScene },
|
||||
.{ CmdID.CmdGetSceneMapInfoCsReq, scene.onGetSceneMapInfo },
|
||||
.{ CmdID.CmdGetUnlockTeleportCsReq, scene.onGetUnlockTeleport },
|
||||
.{ CmdID.CmdEnterSectionCsReq, scene.onEnterSection },
|
||||
.{ CmdID.CmdSceneEntityTeleportCsReq, scene.onSceneEntityTeleport },
|
||||
.{ CmdID.CmdGetFirstTalkNpcCsReq, scene.onGetFirstTalkNpc },
|
||||
.{ CmdID.CmdGetFirstTalkByPerformanceNpcCsReq, scene.onGetFirstTalkByPerformanceNp },
|
||||
.{ CmdID.CmdGetNpcTakenRewardCsReq, scene.onGetNpcTakenReward },
|
||||
.{ CmdID.CmdUpdateGroupPropertyCsReq, scene.onUpdateGroupProperty },
|
||||
.{ CmdID.CmdChangePropTimelineInfoCsReq, scene.onChangePropTimeline },
|
||||
.{ CmdID.CmdDeactivateFarmElementCsReq, scene.onDeactivateFarmElement },
|
||||
.{ CmdID.CmdSetGroupCustomSaveDataCsReq, scene.onSetGroupCustomSaveData },
|
||||
.{ CmdID.CmdGetEnteredSceneCsReq, scene.onGetEnteredScene },
|
||||
//events
|
||||
.{ CmdID.CmdGetActivityScheduleConfigCsReq, events.onGetActivity },
|
||||
.{ CmdID.CmdUpdateServerPrefsDataCsReq, events.onUpdateServerPrefsData },
|
||||
//challenge
|
||||
.{ CmdID.CmdGetChallengeCsReq, challenge.onGetChallenge },
|
||||
.{ CmdID.CmdGetChallengeGroupStatisticsCsReq, challenge.onGetChallengeGroupStatistics },
|
||||
.{ CmdID.CmdStartChallengeCsReq, challenge.onStartChallenge },
|
||||
.{ CmdID.CmdLeaveChallengeCsReq, challenge.onLeaveChallenge },
|
||||
.{ CmdID.CmdGetCurChallengeCsReq, challenge.onGetCurChallengeScRsp },
|
||||
};
|
||||
|
||||
const DummyCmdList = [_]struct { CmdID, CmdID }{
|
||||
.{ CmdID.CmdGetBagCsReq, CmdID.CmdGetBagScRsp },
|
||||
.{ CmdID.CmdGetMarkItemListCsReq, CmdID.CmdGetMarkItemListScRsp },
|
||||
.{ CmdID.CmdGetPlayerBoardDataCsReq, CmdID.CmdGetPlayerBoardDataScRsp },
|
||||
.{ CmdID.CmdGetCurAssistCsReq, CmdID.CmdGetCurAssistScRsp },
|
||||
.{ CmdID.CmdGetAllLineupDataCsReq, CmdID.CmdGetAllLineupDataScRsp },
|
||||
.{ CmdID.CmdGetAllServerPrefsDataCsReq, CmdID.CmdGetAllServerPrefsDataScRsp },
|
||||
.{ CmdID.CmdGetMissionDataCsReq, CmdID.CmdGetMissionDataScRsp },
|
||||
.{ CmdID.CmdGetQuestDataCsReq, CmdID.CmdGetQuestDataScRsp },
|
||||
.{ CmdID.CmdGetRogueCommonDialogueDataCsReq, CmdID.CmdGetRogueCommonDialogueDataScRsp },
|
||||
.{ CmdID.CmdGetRogueInfoCsReq, CmdID.CmdGetRogueInfoScRsp },
|
||||
.{ CmdID.CmdGetRogueHandbookDataCsReq, CmdID.CmdGetRogueHandbookDataScRsp },
|
||||
.{ CmdID.CmdGetRogueEndlessActivityDataCsReq, CmdID.CmdGetRogueEndlessActivityDataScRsp },
|
||||
.{ CmdID.CmdChessRogueQueryCsReq, CmdID.CmdChessRogueQueryScRsp },
|
||||
.{ CmdID.CmdRogueTournQueryCsReq, CmdID.CmdRogueTournQueryScRsp },
|
||||
.{ CmdID.CmdDailyFirstMeetPamCsReq, CmdID.CmdDailyFirstMeetPamScRsp },
|
||||
.{ CmdID.CmdGetBattleCollegeDataCsReq, CmdID.CmdGetBattleCollegeDataScRsp },
|
||||
.{ CmdID.CmdGetNpcStatusCsReq, CmdID.CmdGetNpcStatusScRsp },
|
||||
.{ CmdID.CmdGetSecretKeyInfoCsReq, CmdID.CmdGetSecretKeyInfoScRsp },
|
||||
.{ CmdID.CmdGetHeartDialInfoCsReq, CmdID.CmdGetHeartDialInfoScRsp },
|
||||
.{ CmdID.CmdGetVideoVersionKeyCsReq, CmdID.CmdGetVideoVersionKeyScRsp },
|
||||
.{ CmdID.CmdHeliobusActivityDataCsReq, CmdID.CmdHeliobusActivityDataScRsp },
|
||||
.{ CmdID.CmdGetAetherDivideInfoCsReq, CmdID.CmdGetAetherDivideInfoScRsp },
|
||||
.{ CmdID.CmdGetMapRotationDataCsReq, CmdID.CmdGetMapRotationDataScRsp },
|
||||
.{ CmdID.CmdGetRogueCollectionCsReq, CmdID.CmdGetRogueCollectionScRsp },
|
||||
.{ CmdID.CmdGetRogueExhibitionCsReq, CmdID.CmdGetRogueExhibitionScRsp },
|
||||
.{ CmdID.CmdPlayerReturnInfoQueryCsReq, CmdID.CmdPlayerReturnInfoQueryScRsp },
|
||||
.{ CmdID.CmdGetLevelRewardTakenListCsReq, CmdID.CmdGetLevelRewardTakenListScRsp },
|
||||
.{ CmdID.CmdGetMainMissionCustomValueCsReq, CmdID.CmdGetMainMissionCustomValueScRsp },
|
||||
.{ CmdID.CmdGetMaterialSubmitActivityDataCsReq, CmdID.CmdGetMaterialSubmitActivityDataScRsp },
|
||||
.{ CmdID.CmdRogueTournGetCurRogueCocoonInfoCsReq, CmdID.CmdRogueTournGetCurRogueCocoonInfoScRsp },
|
||||
.{ CmdID.CmdRogueMagicQueryCsReq, CmdID.CmdRogueMagicQueryScRsp },
|
||||
.{ CmdID.CmdMusicRhythmDataCsReq, CmdID.CmdMusicRhythmDataScRsp },
|
||||
//friendlist
|
||||
.{ CmdID.CmdGetFriendApplyListInfoCsReq, CmdID.CmdGetFriendApplyListInfoScRsp },
|
||||
.{ CmdID.CmdGetChatFriendHistoryCsReq, CmdID.CmdGetChatFriendHistoryScRsp },
|
||||
.{ CmdID.CmdGetFriendLoginInfoCsReq, CmdID.CmdGetFriendLoginInfoScRsp },
|
||||
.{ CmdID.CmdGetFriendBattleRecordDetailCsReq, CmdID.CmdGetFriendBattleRecordDetailScRsp },
|
||||
.{ CmdID.CmdGetFriendDevelopmentInfoCsReq, CmdID.CmdGetFriendDevelopmentInfoScRsp },
|
||||
.{ CmdID.CmdGetFriendRecommendListInfoCsReq, CmdID.CmdGetFriendRecommendListInfoScRsp },
|
||||
//add
|
||||
.{ CmdID.CmdSwitchHandDataCsReq, CmdID.CmdSwitchHandDataScRsp },
|
||||
.{ CmdID.CmdRogueArcadeGetInfoCsReq, CmdID.CmdRogueArcadeGetInfoScRsp },
|
||||
.{ CmdID.CmdGetMissionMessageInfoCsReq, CmdID.CmdGetMissionMessageInfoScRsp },
|
||||
.{ CmdID.CmdTrainPartyGetDataCsReq, CmdID.CmdTrainPartyGetDataScRsp },
|
||||
.{ CmdID.CmdQueryProductInfoCsReq, CmdID.CmdQueryProductInfoScRsp },
|
||||
.{ CmdID.CmdGetPamSkinDataCsReq, CmdID.CmdGetPamSkinDataScRsp },
|
||||
.{ CmdID.CmdGetRogueScoreRewardInfoCsReq, CmdID.CmdGetRogueScoreRewardInfoScRsp },
|
||||
.{ CmdID.CmdGetQuestRecordCsReq, CmdID.CmdGetQuestRecordScRsp },
|
||||
.{ CmdID.CmdGetDailyActiveInfoCsReq, CmdID.CmdGetDailyActiveInfoScRsp },
|
||||
.{ CmdID.CmdGetChessRogueNousStoryInfoCsReq, CmdID.CmdGetChessRogueNousStoryInfoScRsp },
|
||||
.{ CmdID.CmdCommonRogueQueryCsReq, CmdID.CmdCommonRogueQueryScRsp },
|
||||
.{ CmdID.CmdGetFightActivityDataCsReq, CmdID.CmdGetFightActivityDataScRsp },
|
||||
.{ CmdID.CmdGetStarFightDataCsReq, CmdID.CmdGetStarFightDataScRsp },
|
||||
.{ CmdID.CmdGetMultipleDropInfoCsReq, CmdID.CmdGetMultipleDropInfoScRsp },
|
||||
.{ CmdID.CmdGetPlayerReturnMultiDropInfoCsReq, CmdID.CmdGetPlayerReturnMultiDropInfoScRsp },
|
||||
.{ CmdID.CmdGetShareDataCsReq, CmdID.CmdGetShareDataScRsp },
|
||||
.{ CmdID.CmdGetTreasureDungeonActivityDataCsReq, CmdID.CmdGetTreasureDungeonActivityDataScRsp },
|
||||
.{ CmdID.CmdEvolveBuildQueryInfoCsReq, CmdID.CmdEvolveBuildQueryInfoScRsp },
|
||||
.{ CmdID.CmdGetAlleyInfoCsReq, CmdID.CmdGetAlleyInfoScRsp },
|
||||
.{ CmdID.CmdGetAetherDivideChallengeInfoCsReq, CmdID.CmdGetAetherDivideChallengeInfoScRsp },
|
||||
.{ CmdID.CmdGetStrongChallengeActivityDataCsReq, CmdID.CmdGetStrongChallengeActivityDataScRsp },
|
||||
.{ CmdID.CmdGetOfferingInfoCsReq, CmdID.CmdGetOfferingInfoScRsp },
|
||||
.{ CmdID.CmdClockParkGetInfoCsReq, CmdID.CmdClockParkGetInfoScRsp },
|
||||
.{ CmdID.CmdGetGunPlayDataCsReq, CmdID.CmdGetGunPlayDataScRsp },
|
||||
.{ CmdID.CmdGetTrackPhotoActivityDataCsReq, CmdID.CmdGetTrackPhotoActivityDataScRsp },
|
||||
.{ CmdID.CmdGetSwordTrainingDataCsReq, CmdID.CmdGetSwordTrainingDataScRsp },
|
||||
.{ CmdID.CmdGetFightFestDataCsReq, CmdID.CmdGetFightFestDataScRsp },
|
||||
.{ CmdID.CmdDifficultyAdjustmentGetDataCsReq, CmdID.CmdDifficultyAdjustmentGetDataScRsp },
|
||||
.{ CmdID.CmdSpaceZooDataCsReq, CmdID.CmdSpaceZooDataScRsp },
|
||||
.{ CmdID.CmdGetExpeditionDataCsReq, CmdID.CmdGetExpeditionDataScRsp },
|
||||
.{ CmdID.CmdTravelBrochureGetDataCsReq, CmdID.CmdTravelBrochureGetDataScRsp },
|
||||
.{ CmdID.CmdRaidCollectionDataCsReq, CmdID.CmdRaidCollectionDataScRsp },
|
||||
.{ CmdID.CmdGetRaidInfoCsReq, CmdID.CmdGetRaidInfoScRsp },
|
||||
.{ CmdID.CmdGetLoginActivityCsReq, CmdID.CmdGetLoginActivityScRsp },
|
||||
.{ CmdID.CmdGetTrialActivityDataCsReq, CmdID.CmdGetTrialActivityDataScRsp },
|
||||
.{ CmdID.CmdGetJukeboxDataCsReq, CmdID.CmdGetJukeboxDataScRsp },
|
||||
.{ CmdID.CmdGetMuseumInfoCsReq, CmdID.CmdGetMuseumInfoScRsp },
|
||||
.{ CmdID.CmdGetTelevisionActivityDataCsReq, CmdID.CmdGetTelevisionActivityDataScRsp },
|
||||
.{ CmdID.CmdGetTrainVisitorRegisterCsReq, CmdID.CmdGetTrainVisitorRegisterScRsp },
|
||||
.{ CmdID.CmdGetBoxingClubInfoCsReq, CmdID.CmdGetBoxingClubInfoScRsp },
|
||||
.{ CmdID.CmdTextJoinQueryCsReq, CmdID.CmdTextJoinQueryScRsp },
|
||||
.{ CmdID.CmdGetLoginChatInfoCsReq, CmdID.CmdGetLoginChatInfoScRsp },
|
||||
.{ CmdID.CmdGetFeverTimeActivityDataCsReq, CmdID.CmdGetFeverTimeActivityDataScRsp },
|
||||
.{ CmdID.CmdGetSummonActivityDataCsReq, CmdID.CmdGetSummonActivityDataScRsp },
|
||||
.{ CmdID.CmdTarotBookGetDataCsReq, CmdID.CmdTarotBookGetDataScRsp },
|
||||
.{ CmdID.CmdGetMarkChestCsReq, CmdID.CmdGetMarkChestScRsp },
|
||||
.{ CmdID.CmdMatchThreeGetDataCsReq, CmdID.CmdMatchThreeGetDataScRsp },
|
||||
.{ CmdID.CmdUpdateTrackMainMissionIdCsReq, CmdID.CmdUpdateTrackMainMissionIdScRsp },
|
||||
.{ CmdID.CmdGetNpcMessageGroupCsReq, CmdID.CmdGetNpcMessageGroupScRsp },
|
||||
.{ CmdID.CmdGetAllSaveRaidCsReq, CmdID.CmdGetAllSaveRaidScRsp },
|
||||
.{ CmdID.CmdGetAssistHistoryCsReq, CmdID.CmdGetAssistHistoryScRsp },
|
||||
.{ CmdID.CmdGetPlayerDetailInfoCsReq, CmdID.CmdGetPlayerDetailInfoScRsp },
|
||||
.{ CmdID.CmdGetEraFlipperDataCsReq, CmdID.CmdGetEraFlipperDataScRsp },
|
||||
//.{ CmdID.CmdGetPreAvatarListCsReq, CmdID.CmdGetPreAvatarListScRsp },
|
||||
.{ CmdID.CmdGetRechargeGiftInfoCsReq, CmdID.CmdGetRechargeGiftInfoScRsp },
|
||||
.{ CmdID.CmdGetRechargeBenefitInfoCsReq, CmdID.CmdGetRechargeBenefitInfoScRsp },
|
||||
.{ CmdID.CmdRelicSmartWearGetPlanCsReq, CmdID.CmdRelicSmartWearGetPlanScRsp },
|
||||
.{ CmdID.CmdRelicSmartWearGetPinRelicCsReq, CmdID.CmdRelicSmartWearGetPinRelicScRsp },
|
||||
.{ CmdID.CmdSetGrowthTargetAvatarCsReq, CmdID.CmdSetGrowthTargetAvatarScRsp },
|
||||
};
|
||||
|
||||
const SuppressLogList = [_]CmdID{CmdID.CmdSceneEntityMoveCsReq};
|
||||
|
||||
pub fn handle(session: *Session, packet: *const Packet) !void {
|
||||
var arena = ArenaAllocator.init(session.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const cmd_id: CmdID = @enumFromInt(packet.cmd_id);
|
||||
|
||||
inline for (HandlerList) |handler| {
|
||||
if (handler[0] == cmd_id) {
|
||||
try handler[1](session, packet, arena.allocator());
|
||||
if (!std.mem.containsAtLeast(CmdID, &SuppressLogList, 1, &[_]CmdID{cmd_id})) {
|
||||
log.debug("packet {} was handled", .{cmd_id});
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inline for (DummyCmdList) |pair| {
|
||||
if (pair[0] == cmd_id) {
|
||||
try session.send_empty(pair[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log.warn("packet {} was ignored", .{cmd_id});
|
||||
}
|
15
gameserver/src/main.zig
Normal file
15
gameserver/src/main.zig
Normal file
|
@ -0,0 +1,15 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const network = @import("network.zig");
|
||||
const handlers = @import("handlers.zig");
|
||||
|
||||
pub const std_options = .{
|
||||
.log_level = switch (builtin.mode) {
|
||||
.Debug => .debug,
|
||||
else => .info,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
try network.listen();
|
||||
}
|
339
gameserver/src/manager/battle_mgr.zig
Normal file
339
gameserver/src/manager/battle_mgr.zig
Normal file
|
@ -0,0 +1,339 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("../services/config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const ChallengeData = @import("../services/challenge.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub var selectedAvatarID = [_]u32{ 1304, 1313, 1406, 1004 };
|
||||
|
||||
// Function to check if an ID is in a list
|
||||
fn isInList(id: u32, list: []const u32) bool {
|
||||
for (list) |item| {
|
||||
if (item == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
fn createBattleRelic(allocator: Allocator, id: u32, level: u32, main_affix_id: u32, stat1: u32, cnt1: u32, step1: u32, stat2: u32, cnt2: u32, step2: u32, stat3: u32, cnt3: u32, step3: u32, stat4: u32, cnt4: u32, step4: u32) !protocol.BattleRelic {
|
||||
var relic = protocol.BattleRelic{
|
||||
.id = id,
|
||||
.main_affix_id = main_affix_id,
|
||||
.level = level,
|
||||
.sub_affix_list = ArrayList(protocol.RelicAffix).init(allocator),
|
||||
};
|
||||
try relic.sub_affix_list.append(protocol.RelicAffix{ .affix_id = stat1, .cnt = cnt1, .step = step1 });
|
||||
try relic.sub_affix_list.append(protocol.RelicAffix{ .affix_id = stat2, .cnt = cnt2, .step = step2 });
|
||||
try relic.sub_affix_list.append(protocol.RelicAffix{ .affix_id = stat3, .cnt = cnt3, .step = step3 });
|
||||
try relic.sub_affix_list.append(protocol.RelicAffix{ .affix_id = stat4, .cnt = cnt4, .step = step4 });
|
||||
return relic;
|
||||
}
|
||||
fn createBattleAvatar(allocator: Allocator, avatarConf: Config.Avatar) !protocol.BattleAvatar {
|
||||
var avatar = protocol.BattleAvatar.init(allocator);
|
||||
avatar.id = avatarConf.id;
|
||||
avatar.hp = avatarConf.hp * 100;
|
||||
avatar.sp_bar = .{ .sp_cur = avatarConf.sp * 100, .sp_max = 10000 };
|
||||
avatar.level = avatarConf.level;
|
||||
avatar.rank = avatarConf.rank;
|
||||
avatar.promotion = avatarConf.promotion;
|
||||
avatar.avatar_type = .AVATAR_FORMAL_TYPE;
|
||||
if (isInList(avatar.id, &Data.EnhanceAvatarID)) avatar.GLACKHOPMIO = 1;
|
||||
|
||||
// Relics
|
||||
for (avatarConf.relics.items) |relic| {
|
||||
const r = try createBattleRelic(allocator, relic.id, relic.level, relic.main_affix_id, relic.stat1, relic.cnt1, relic.step1, relic.stat2, relic.cnt2, relic.step2, relic.stat3, relic.cnt3, relic.step3, relic.stat4, relic.cnt4, relic.step4);
|
||||
try avatar.relic_list.append(r);
|
||||
}
|
||||
|
||||
// Lightcone
|
||||
const lc = protocol.BattleEquipment{
|
||||
.id = avatarConf.lightcone.id,
|
||||
.rank = avatarConf.lightcone.rank,
|
||||
.level = avatarConf.lightcone.level,
|
||||
.promotion = avatarConf.lightcone.promotion,
|
||||
};
|
||||
try avatar.equipment_list.append(lc);
|
||||
|
||||
// Skills
|
||||
var talentLevel: u32 = 0;
|
||||
const skill_list: []const u32 = if (isInList(avatar.id, &Data.Rem)) &Data.skills else &Data.skills_old;
|
||||
for (skill_list) |elem| {
|
||||
talentLevel = switch (elem) {
|
||||
1 => 6,
|
||||
2...4 => 10,
|
||||
301, 302 => if (isInList(avatar.id, &Data.Rem)) 6 else 1,
|
||||
else => 1,
|
||||
};
|
||||
var point_id: u32 = 0;
|
||||
if (isInList(avatar.id, &Data.EnhanceAvatarID)) point_id = avatar.id + 10000 else point_id = avatar.id;
|
||||
const talent = protocol.AvatarSkillTree{ .point_id = point_id * 1000 + elem, .level = talentLevel };
|
||||
try avatar.skilltree_list.append(talent);
|
||||
}
|
||||
return avatar;
|
||||
}
|
||||
|
||||
// Function to add technique buffs
|
||||
fn addTechniqueBuffs(allocator: Allocator, battle: *protocol.SceneBattleInfo, avatar: protocol.BattleAvatar, avatarConf: Config.Avatar, avatar_index: u32) !void {
|
||||
if (!avatarConf.use_technique) return;
|
||||
|
||||
var targetIndexList = ArrayList(u32).init(allocator);
|
||||
try targetIndexList.append(0);
|
||||
|
||||
var buffedAvatarId = avatar.id;
|
||||
if (avatar.id == 8004) {
|
||||
buffedAvatarId = 8003;
|
||||
} else if (avatar.id == 8006) {
|
||||
buffedAvatarId = 8005;
|
||||
} else if (avatar.id == 8008) {
|
||||
buffedAvatarId = 8007;
|
||||
}
|
||||
|
||||
for (Data.buffs_unlocked) |buffId| {
|
||||
const idPrefix = buffId / 100;
|
||||
if (idPrefix == buffedAvatarId) {
|
||||
var buff = protocol.BattleBuff{
|
||||
.id = buffId,
|
||||
.level = 1,
|
||||
.owner_index = @intCast(avatar_index),
|
||||
.wave_flag = 1,
|
||||
.target_index_list = targetIndexList,
|
||||
.dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(allocator),
|
||||
};
|
||||
try buff.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 });
|
||||
try battle.buff_list.append(buff);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInList(buffedAvatarId, &Data.IgnoreToughness)) {
|
||||
var buff_tough = protocol.BattleBuff{
|
||||
.id = 1000119, //for is_ignore toughness
|
||||
.level = 1,
|
||||
.owner_index = @intCast(avatar_index),
|
||||
.wave_flag = 1,
|
||||
.target_index_list = targetIndexList,
|
||||
.dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(allocator),
|
||||
};
|
||||
try buff_tough.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 });
|
||||
try battle.buff_list.append(buff_tough);
|
||||
}
|
||||
|
||||
if (buffedAvatarId == 1224) {
|
||||
var buff_march = protocol.BattleBuff{
|
||||
.id = 122401, //for hunt march 7th tech
|
||||
.level = 1,
|
||||
.owner_index = @intCast(avatar_index),
|
||||
.wave_flag = 1,
|
||||
.target_index_list = targetIndexList,
|
||||
.dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(allocator),
|
||||
};
|
||||
try buff_march.dynamic_values.appendSlice(&[_]protocol.BattleBuff.DynamicValuesEntry{
|
||||
.{ .key = .{ .Const = "#ADF_1" }, .value = 3 },
|
||||
.{ .key = .{ .Const = "#ADF_2" }, .value = 3 },
|
||||
});
|
||||
try battle.buff_list.append(buff_march);
|
||||
}
|
||||
|
||||
if (buffedAvatarId == 1310) {
|
||||
var buff_firefly = protocol.BattleBuff{
|
||||
.id = 1000112, //for firefly tech
|
||||
.level = 1,
|
||||
.owner_index = @intCast(avatar_index),
|
||||
.wave_flag = 1,
|
||||
.target_index_list = targetIndexList,
|
||||
.dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(allocator),
|
||||
};
|
||||
try buff_firefly.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 });
|
||||
try battle.buff_list.append(buff_firefly);
|
||||
}
|
||||
|
||||
if (buffedAvatarId == 8007) {
|
||||
var buff_rmc = protocol.BattleBuff{
|
||||
.id = 800701, //for rmc tech
|
||||
.level = 1,
|
||||
.owner_index = @intCast(avatar_index),
|
||||
.wave_flag = 1,
|
||||
.target_index_list = targetIndexList,
|
||||
.dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(allocator),
|
||||
};
|
||||
try buff_rmc.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 });
|
||||
try battle.buff_list.append(buff_rmc);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to add future global buff.
|
||||
fn addGolbalPassive(allocator: Allocator, battle: *protocol.SceneBattleInfo, wave_flag: u32) !void {
|
||||
if (isInList(1407, Data.AllAvatars)) { //support Castorice
|
||||
var targetIndexList = ArrayList(u32).init(allocator);
|
||||
try targetIndexList.append(0);
|
||||
var mazebuff_data = protocol.BattleBuff{
|
||||
.id = 140703,
|
||||
.level = 1,
|
||||
.owner_index = 1,
|
||||
.wave_flag = wave_flag,
|
||||
.target_index_list = targetIndexList,
|
||||
.dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(allocator),
|
||||
};
|
||||
try mazebuff_data.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 });
|
||||
try battle.buff_list.append(mazebuff_data);
|
||||
}
|
||||
}
|
||||
fn createBattleInfo(allocator: Allocator, config: Config.GameConfig, stage_monster_wave_len: u32, stage_id: u32, rounds_limit: u32) protocol.SceneBattleInfo {
|
||||
var battle = protocol.SceneBattleInfo.init(allocator);
|
||||
battle.battle_id = config.battle_config.battle_id;
|
||||
battle.stage_id = stage_id;
|
||||
battle.logic_random_seed = @intCast(@mod(std.time.timestamp(), 0xFFFFFFFF));
|
||||
battle.rounds_limit = rounds_limit;
|
||||
battle.monster_wave_length = @intCast(stage_monster_wave_len);
|
||||
battle.world_level = 6;
|
||||
return battle;
|
||||
}
|
||||
fn addMonsterWaves(allocator: Allocator, battle: *protocol.SceneBattleInfo, monster_wave_configs: std.ArrayList(std.ArrayList(u32)), monster_level: u32) !void { // Added monster_level
|
||||
for (monster_wave_configs.items) |wave| {
|
||||
var monster_wave = protocol.SceneMonsterWave.init(allocator);
|
||||
monster_wave.wave_param = protocol.SceneMonsterWaveParam{ .level = monster_level };
|
||||
for (wave.items) |mob_id| {
|
||||
try monster_wave.monster_list.append(.{ .monster_id = mob_id });
|
||||
}
|
||||
try battle.monster_wave_list.append(monster_wave);
|
||||
}
|
||||
}
|
||||
fn addStageBlessings(allocator: Allocator, battle: *protocol.SceneBattleInfo, blessings: []const u32) !void {
|
||||
for (blessings) |blessing| {
|
||||
var targetIndexList = ArrayList(u32).init(allocator);
|
||||
try targetIndexList.append(0);
|
||||
var buff = protocol.BattleBuff{
|
||||
.id = blessing,
|
||||
.level = 1,
|
||||
.owner_index = 0xffffffff,
|
||||
.wave_flag = 0xffffffff,
|
||||
.target_index_list = targetIndexList,
|
||||
.dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(allocator),
|
||||
};
|
||||
try buff.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 });
|
||||
try battle.buff_list.append(buff);
|
||||
}
|
||||
}
|
||||
fn addBattleTargets(allocator: Allocator, battle: *protocol.SceneBattleInfo) !void {
|
||||
// PF/AS scoring
|
||||
battle.battle_target_info = ArrayList(protocol.SceneBattleInfo.BattleTargetInfoEntry).init(allocator);
|
||||
|
||||
// target hardcode
|
||||
var pfTargetHead = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(allocator) };
|
||||
try pfTargetHead.battle_target_list.append(.{ .id = 10002, .progress = 0, .total_progress = 0 });
|
||||
var pfTargetTail = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(allocator) };
|
||||
try pfTargetTail.battle_target_list.append(.{ .id = 2001, .progress = 0, .total_progress = 0 });
|
||||
try pfTargetTail.battle_target_list.append(.{ .id = 2002, .progress = 0, .total_progress = 0 });
|
||||
var asTargetHead = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(allocator) };
|
||||
try asTargetHead.battle_target_list.append(.{ .id = 90005, .progress = 0, .total_progress = 0 });
|
||||
|
||||
switch (battle.stage_id) {
|
||||
// PF
|
||||
30019000...30019100, 30021000...30021100, 30301000...30319000 => {
|
||||
try battle.battle_target_info.append(.{ .key = 1, .value = pfTargetHead });
|
||||
// fill blank target
|
||||
for (2..5) |i| {
|
||||
try battle.battle_target_info.append(.{ .key = @intCast(i) });
|
||||
}
|
||||
try battle.battle_target_info.append(.{ .key = 5, .value = pfTargetTail });
|
||||
},
|
||||
// AS
|
||||
420100...420300 => {
|
||||
try battle.battle_target_info.append(.{ .key = 1, .value = asTargetHead });
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
pub const BattleManager = struct {
|
||||
allocator: Allocator,
|
||||
|
||||
pub fn init(allocator: Allocator) BattleManager {
|
||||
return BattleManager{ .allocator = allocator };
|
||||
}
|
||||
|
||||
pub fn createBattle(self: *BattleManager) !protocol.SceneBattleInfo {
|
||||
const config = try Config.loadGameConfig(self.allocator, "config.json");
|
||||
var battle = createBattleInfo(self.allocator, config, @intCast(config.battle_config.monster_wave.items.len), config.battle_config.stage_id, config.battle_config.cycle_count);
|
||||
var avatarIndex: u32 = 0;
|
||||
var initial_mode = false;
|
||||
while (true) {
|
||||
if (!initial_mode) {
|
||||
for (selectedAvatarID) |selected_id| {
|
||||
for (config.avatar_config.items) |avatarConf| {
|
||||
if (avatarConf.id == selected_id) {
|
||||
const avatar = try createBattleAvatar(self.allocator, avatarConf);
|
||||
try addTechniqueBuffs(self.allocator, &battle, avatar, avatarConf, avatarIndex);
|
||||
try battle.pve_avatar_list.append(avatar);
|
||||
avatarIndex += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (avatarIndex >= 4) break;
|
||||
}
|
||||
}
|
||||
if (avatarIndex == 0 and !initial_mode) {
|
||||
initial_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
try addMonsterWaves(self.allocator, &battle, config.battle_config.monster_wave, config.battle_config.monster_level);
|
||||
try addStageBlessings(self.allocator, &battle, config.battle_config.blessings.items);
|
||||
try addGolbalPassive(self.allocator, &battle, @intCast(config.battle_config.monster_wave.items.len));
|
||||
try addBattleTargets(self.allocator, &battle);
|
||||
return battle;
|
||||
}
|
||||
};
|
||||
|
||||
pub const ChallegeStageManager = struct {
|
||||
allocator: Allocator,
|
||||
|
||||
pub fn init(allocator: Allocator) ChallegeStageManager {
|
||||
return ChallegeStageManager{ .allocator = allocator };
|
||||
}
|
||||
|
||||
pub fn createChallegeStage(self: *ChallegeStageManager) !protocol.SceneBattleInfo {
|
||||
const config = try Config.loadGameConfig(self.allocator, "config.json");
|
||||
const stage = try Config.loadStageConfig(self.allocator, "resources/StageConfig.json");
|
||||
var battle: protocol.SceneBattleInfo = undefined;
|
||||
for (stage.stage_config.items) |stageConf| {
|
||||
if (stageConf.stage_id == ChallengeData.challenge_stageID) {
|
||||
battle = createBattleInfo(self.allocator, config, @intCast(stageConf.monster_list.items.len), stageConf.stage_id, if (ChallengeData.challenge_mode != 1) 30 else 4);
|
||||
var avatarIndex: u32 = 0;
|
||||
var initial_mode = false;
|
||||
while (true) {
|
||||
if (!initial_mode) {
|
||||
for (selectedAvatarID) |selected_id| {
|
||||
for (config.avatar_config.items) |avatarConf| {
|
||||
if (avatarConf.id == selected_id) {
|
||||
const avatar = try createBattleAvatar(self.allocator, avatarConf);
|
||||
try addTechniqueBuffs(self.allocator, &battle, avatar, avatarConf, avatarIndex);
|
||||
try battle.pve_avatar_list.append(avatar);
|
||||
avatarIndex += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (avatarIndex >= 4) break;
|
||||
}
|
||||
}
|
||||
if (avatarIndex == 0 and !initial_mode) {
|
||||
initial_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
try addMonsterWaves(self.allocator, &battle, stageConf.monster_list, stageConf.level);
|
||||
try addStageBlessings(self.allocator, &battle, ChallengeData.challenge_blessing);
|
||||
try addGolbalPassive(self.allocator, &battle, @intCast(stageConf.monster_list.items.len));
|
||||
try addBattleTargets(self.allocator, &battle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return battle;
|
||||
}
|
||||
};
|
158
gameserver/src/manager/challenge_mgr.zig
Normal file
158
gameserver/src/manager/challenge_mgr.zig
Normal file
|
@ -0,0 +1,158 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("../services/config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const ChallengeData = @import("../services/challenge.zig");
|
||||
const NodeCheck = @import("../commands/value.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
fn contains(list: *const std.ArrayListAligned(u32, null), value: u32) bool {
|
||||
for (list.items) |item| {
|
||||
if (item == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub const ChallengeManager = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
pub fn init(allocator: std.mem.Allocator) ChallengeManager {
|
||||
return ChallengeManager{ .allocator = allocator };
|
||||
}
|
||||
pub fn createChallenge(
|
||||
self: *ChallengeManager,
|
||||
challenge_id: u32,
|
||||
buff_id: u32,
|
||||
) !protocol.CurChallenge {
|
||||
const challenge_config = try Config.loadChallengeConfig(self.allocator, "resources/ChallengeMazeConfig.json");
|
||||
const entrance_config = try Config.loadMapEntranceConfig(self.allocator, "resources/MapEntrance.json");
|
||||
const maze_config = try Config.loadMazePlaneConfig(self.allocator, "resources/MazePlane.json");
|
||||
|
||||
var challenge_blessing_list = ChallengeData.ChallengeBlessing{
|
||||
.allocator = std.heap.page_allocator,
|
||||
.items = &.{},
|
||||
.capacity = 0,
|
||||
};
|
||||
|
||||
var cur_challenge_info = protocol.CurChallenge.init(self.allocator);
|
||||
cur_challenge_info.challenge_id = challenge_id;
|
||||
cur_challenge_info.score_id = if (challenge_id > 20000 and challenge_id < 30000) 40000 else 0;
|
||||
cur_challenge_info.score_two = 0;
|
||||
cur_challenge_info.status = protocol.ChallengeStatus.CHALLENGE_DOING;
|
||||
cur_challenge_info.extra_lineup_type = if (NodeCheck.challenge_node == 0) protocol.ExtraLineupType.LINEUP_CHALLENGE else protocol.ExtraLineupType.LINEUP_CHALLENGE_2;
|
||||
if (NodeCheck.challenge_node == 0) {
|
||||
for (challenge_config.challenge_config.items) |challengeConf| {
|
||||
if (challengeConf.id == challenge_id) {
|
||||
std.debug.print("TRACING CONFIG ID {} WITH CHALLENGE ID {}\n", .{ challengeConf.id, challenge_id });
|
||||
for (entrance_config.map_entrance_config.items) |entrance| {
|
||||
if (entrance.id == challengeConf.map_entrance_id) {
|
||||
for (maze_config.maze_plane_config.items) |maze| {
|
||||
if (contains(&maze.floor_id_list, entrance.floor_id)) {
|
||||
if (challenge_id > 20000 and challenge_id < 30000) {
|
||||
var story_buff = protocol.ChallengeStoryBuffList{
|
||||
.buff_list = ArrayList(u32).init(self.allocator),
|
||||
};
|
||||
try story_buff.buff_list.append(challengeConf.maze_buff_id);
|
||||
try story_buff.buff_list.append(buff_id);
|
||||
try challenge_blessing_list.appendSlice(story_buff.buff_list.items);
|
||||
cur_challenge_info.stage_info = .{
|
||||
.IEICDGGELNE = .{
|
||||
.cur_story_buffs = story_buff,
|
||||
},
|
||||
};
|
||||
ChallengeData.challenge_mode = 1;
|
||||
} else if (challenge_id > 30000) {
|
||||
var boss_buff = protocol.ChallengeBossBuffList{
|
||||
.buff_list = ArrayList(u32).init(self.allocator),
|
||||
.challenge_boss_const = 1,
|
||||
};
|
||||
try boss_buff.buff_list.append(challengeConf.maze_buff_id);
|
||||
try boss_buff.buff_list.append(buff_id);
|
||||
try challenge_blessing_list.appendSlice(boss_buff.buff_list.items);
|
||||
cur_challenge_info.stage_info = .{
|
||||
.IEICDGGELNE = .{
|
||||
.cur_boss_buffs = boss_buff,
|
||||
},
|
||||
};
|
||||
ChallengeData.challenge_mode = 2;
|
||||
}
|
||||
ChallengeData.challenge_floorID = entrance.floor_id;
|
||||
ChallengeData.challenge_worldID = maze.world_id;
|
||||
ChallengeData.challenge_monsterID = challengeConf.npc_monster_id_list1.items[challengeConf.npc_monster_id_list1.items.len - 1];
|
||||
ChallengeData.challenge_eventID = challengeConf.event_id_list1.items[challengeConf.event_id_list1.items.len - 1];
|
||||
ChallengeData.challenge_groupID = challengeConf.maze_group_id1;
|
||||
ChallengeData.challenge_maze_groupID = challengeConf.maze_group_id1;
|
||||
ChallengeData.challenge_planeID = maze.challenge_plane_id;
|
||||
ChallengeData.challenge_entryID = challengeConf.map_entrance_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (challenge_config.challenge_config.items) |challengeConf| {
|
||||
if (challengeConf.id == challenge_id) {
|
||||
std.debug.print("TRACING CONFIG ID {} WITH CHALLENGE ID {}\n", .{ challengeConf.id, challenge_id });
|
||||
for (entrance_config.map_entrance_config.items) |entrance| {
|
||||
if (entrance.id == challengeConf.map_entrance_id2) {
|
||||
for (maze_config.maze_plane_config.items) |maze| {
|
||||
if (contains(&maze.floor_id_list, entrance.floor_id)) {
|
||||
if (challengeConf.maze_group_id2) |id| {
|
||||
if (challenge_id > 20000 and challenge_id < 30000) {
|
||||
var story_buff = protocol.ChallengeStoryBuffList{
|
||||
.buff_list = ArrayList(u32).init(self.allocator),
|
||||
};
|
||||
try story_buff.buff_list.append(challengeConf.maze_buff_id);
|
||||
try story_buff.buff_list.append(buff_id);
|
||||
try challenge_blessing_list.appendSlice(story_buff.buff_list.items);
|
||||
cur_challenge_info.stage_info = .{
|
||||
.IEICDGGELNE = .{
|
||||
.cur_story_buffs = story_buff,
|
||||
},
|
||||
};
|
||||
ChallengeData.challenge_mode = 1;
|
||||
} else if (challenge_id > 30000) {
|
||||
var boss_buff = protocol.ChallengeBossBuffList{
|
||||
.buff_list = ArrayList(u32).init(self.allocator),
|
||||
.challenge_boss_const = 1,
|
||||
};
|
||||
try boss_buff.buff_list.append(challengeConf.maze_buff_id);
|
||||
try boss_buff.buff_list.append(buff_id);
|
||||
try challenge_blessing_list.appendSlice(boss_buff.buff_list.items);
|
||||
cur_challenge_info.stage_info = .{
|
||||
.IEICDGGELNE = .{
|
||||
.cur_boss_buffs = boss_buff,
|
||||
},
|
||||
};
|
||||
ChallengeData.challenge_mode = 2;
|
||||
}
|
||||
ChallengeData.challenge_floorID = entrance.floor_id;
|
||||
ChallengeData.challenge_worldID = maze.world_id;
|
||||
ChallengeData.challenge_monsterID = challengeConf.npc_monster_id_list2.items[challengeConf.npc_monster_id_list2.items.len - 1];
|
||||
ChallengeData.challenge_eventID = challengeConf.event_id_list2.items[challengeConf.event_id_list2.items.len - 1];
|
||||
ChallengeData.challenge_groupID = id;
|
||||
ChallengeData.challenge_maze_groupID = id;
|
||||
ChallengeData.challenge_planeID = maze.challenge_plane_id;
|
||||
ChallengeData.challenge_entryID = challengeConf.map_entrance_id2;
|
||||
} else {
|
||||
std.debug.print("THIS CHALLENGE ID: {} DOES NOT SUPPORT 2ND NODE. PLEASE DO COMMAND /node TO SWITCH BACK TO FIRST NODE\n", .{challenge_id});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ChallengeData.challenge_blessing = challenge_blessing_list.items[0..challenge_blessing_list.items.len];
|
||||
ChallengeData.challenge_stageID = ChallengeData.challenge_eventID;
|
||||
return cur_challenge_info;
|
||||
}
|
||||
};
|
109
gameserver/src/manager/lineup_mgr.zig
Normal file
109
gameserver/src/manager/lineup_mgr.zig
Normal file
|
@ -0,0 +1,109 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("../services/config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const ChallengeData = @import("../services/challenge.zig");
|
||||
const NodeCheck = @import("../commands/value.zig");
|
||||
const BattleManager = @import("../manager/battle_mgr.zig");
|
||||
|
||||
const UidGenerator = @import("../services/item.zig").UidGenerator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub const LineupManager = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
pub fn init(allocator: std.mem.Allocator) LineupManager {
|
||||
return LineupManager{ .allocator = allocator };
|
||||
}
|
||||
pub fn createLineup(self: *LineupManager) !protocol.LineupInfo {
|
||||
const config = try Config.loadGameConfig(self.allocator, "config.json");
|
||||
|
||||
var lineup = protocol.LineupInfo.init(self.allocator);
|
||||
lineup.mp = 5;
|
||||
lineup.max_mp = 5;
|
||||
lineup.name = .{ .Const = "JingliuSR" };
|
||||
|
||||
for (config.avatar_config.items, 0..) |avatarConf, idx| {
|
||||
if (idx >= 4) {
|
||||
break;
|
||||
}
|
||||
var avatar = protocol.LineupAvatar.init(self.allocator);
|
||||
avatar.id = avatarConf.id;
|
||||
avatar.slot = @intCast(idx);
|
||||
avatar.satiety = 0;
|
||||
avatar.hp = avatarConf.hp * 100;
|
||||
avatar.sp_bar = .{ .sp_cur = avatarConf.sp * 100, .sp_max = 10000 };
|
||||
avatar.avatar_type = protocol.AvatarType.AVATAR_FORMAL_TYPE;
|
||||
try lineup.avatar_list.append(avatar);
|
||||
}
|
||||
var id_list = try self.allocator.alloc(u32, config.avatar_config.items.len);
|
||||
defer self.allocator.free(id_list);
|
||||
for (config.avatar_config.items, 0..) |slot, idx| {
|
||||
if (idx >= 4) {
|
||||
break;
|
||||
}
|
||||
id_list[idx] = slot.id;
|
||||
}
|
||||
try getSelectedAvatarID(self.allocator, id_list);
|
||||
return lineup;
|
||||
}
|
||||
};
|
||||
|
||||
pub const ChallengeLineupManager = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
pub fn init(allocator: std.mem.Allocator) ChallengeLineupManager {
|
||||
return ChallengeLineupManager{ .allocator = allocator };
|
||||
}
|
||||
pub fn createLineup(
|
||||
self: *ChallengeLineupManager,
|
||||
avatar_list: ArrayList(u32),
|
||||
) !protocol.LineupInfo {
|
||||
var lineup = protocol.LineupInfo.init(self.allocator);
|
||||
lineup.mp = 5;
|
||||
lineup.max_mp = 5;
|
||||
lineup.extra_lineup_type = if (NodeCheck.challenge_node == 0) protocol.ExtraLineupType.LINEUP_CHALLENGE else protocol.ExtraLineupType.LINEUP_CHALLENGE_2;
|
||||
|
||||
for (avatar_list.items, 0..) |avatarlist, idx| {
|
||||
var avatar = protocol.LineupAvatar.init(self.allocator);
|
||||
avatar.id = avatarlist;
|
||||
avatar.slot = @intCast(idx);
|
||||
avatar.satiety = 0;
|
||||
avatar.hp = 10000;
|
||||
avatar.sp_bar = .{ .sp_cur = 10000, .sp_max = 10000 };
|
||||
avatar.avatar_type = protocol.AvatarType.AVATAR_FORMAL_TYPE;
|
||||
try lineup.avatar_list.append(avatar);
|
||||
}
|
||||
var id_list = try self.allocator.alloc(u32, avatar_list.items.len);
|
||||
defer self.allocator.free(id_list);
|
||||
for (avatar_list.items, 0..) |slot, idx| {
|
||||
if (idx >= 4) {
|
||||
break;
|
||||
}
|
||||
id_list[idx] = slot;
|
||||
}
|
||||
try getSelectedAvatarID(self.allocator, id_list);
|
||||
return lineup;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn getSelectedAvatarID(allocator: std.mem.Allocator, input: []const u32) !void {
|
||||
var tempList = std.ArrayList(u32).init(allocator);
|
||||
defer tempList.deinit();
|
||||
|
||||
try tempList.appendSlice(input);
|
||||
for (tempList.items) |*item| {
|
||||
if (item.* == 8001) {
|
||||
item.* = 8008;
|
||||
}
|
||||
}
|
||||
var i: usize = 0;
|
||||
while (i < BattleManager.selectedAvatarID.len and i < tempList.items.len) : (i += 1) {
|
||||
BattleManager.selectedAvatarID[i] = tempList.items[i];
|
||||
}
|
||||
while (i < BattleManager.selectedAvatarID.len) : (i += 1) {
|
||||
BattleManager.selectedAvatarID[i] = 0;
|
||||
}
|
||||
}
|
110
gameserver/src/manager/multipath_mgr.zig
Normal file
110
gameserver/src/manager/multipath_mgr.zig
Normal file
|
@ -0,0 +1,110 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("../services/config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub const MultiPathManager = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
pub fn init(allocator: std.mem.Allocator) MultiPathManager {
|
||||
return MultiPathManager{ .allocator = allocator };
|
||||
}
|
||||
pub fn createMultiPath(self: *MultiPathManager, skinID: u32) !protocol.GetMultiPathAvatarInfoScRsp {
|
||||
var rsp = protocol.GetMultiPathAvatarInfoScRsp.init(self.allocator);
|
||||
const config = try Config.loadGameConfig(self.allocator, "config.json");
|
||||
const GeneratorType = UidGenerator();
|
||||
const avatar_ids = [_][]const u32{
|
||||
&[_]u32{ 8001, 8002 },
|
||||
&[_]u32{ 8003, 8004 },
|
||||
&[_]u32{ 8005, 8006 },
|
||||
&[_]u32{ 8007, 8008 },
|
||||
&[_]u32{1001},
|
||||
&[_]u32{1224},
|
||||
};
|
||||
const avatar_types = [_]protocol.MultiPathAvatarType{
|
||||
.GirlWarriorType, .GirlKnightType, .GirlShamanType,
|
||||
.GirlMemoryType, .Mar_7thKnightType, .Mar_7thRogueType,
|
||||
};
|
||||
var indexes: [6]u32 = [_]u32{0} ** 6;
|
||||
var counts: [6]u32 = [_]u32{0} ** 6;
|
||||
var multis: [6]protocol.MultiPathAvatarInfo = undefined;
|
||||
for (&multis, avatar_types, 0..) |*multi, avatar_type, i| {
|
||||
std.debug.print("MULTIPATH AVATAR INDEX: {} IS {}\n", .{ i, avatar_type });
|
||||
multi.* = protocol.MultiPathAvatarInfo.init(self.allocator);
|
||||
multi.avatar_id = avatar_type;
|
||||
if (avatar_type == .Mar_7thKnightType) {
|
||||
multi.dressed_skin_id = skinID;
|
||||
}
|
||||
}
|
||||
for (config.avatar_config.items) |avatar| {
|
||||
for (0..avatar_ids.len) |i| {
|
||||
counts[i] += 1;
|
||||
for (avatar_ids[i]) |id| {
|
||||
if (avatar.id == id) {
|
||||
multis[i].rank = avatar.rank;
|
||||
indexes[i] = counts[i] - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var generators: [6]GeneratorType = undefined;
|
||||
for (0..multis.len) |i| {
|
||||
generators[i] = GeneratorType.init(indexes[i] * 7 + 1);
|
||||
}
|
||||
for (0..multis.len) |i| {
|
||||
var multi = &multis[i];
|
||||
var gen = &generators[i];
|
||||
|
||||
multi.path_equipment_id = indexes[i] * 7 + 1;
|
||||
multi.equip_relic_list = ArrayList(protocol.EquipRelic).init(self.allocator);
|
||||
|
||||
for (0..6) |slot| {
|
||||
try multi.equip_relic_list.append(.{
|
||||
.relic_unique_id = gen.nextId(),
|
||||
.type = @intCast(slot),
|
||||
});
|
||||
}
|
||||
}
|
||||
for (0..multis.len) |i| {
|
||||
const skill_set = if (i == 3) &Data.skills else &Data.skills_old;
|
||||
for (skill_set) |skill| {
|
||||
const talent_level: u32 = if (skill == 1 or skill == 301 or skill == 302) 6 else if (skill <= 4) 10 else 1;
|
||||
const point_id = if (avatar_ids[i].len > 1)
|
||||
avatar_ids[i][1] * 1000 + skill
|
||||
else
|
||||
avatar_ids[i][0] * 1000 + skill;
|
||||
const talent = protocol.AvatarSkillTree{
|
||||
.point_id = point_id,
|
||||
.level = talent_level,
|
||||
};
|
||||
try multis[i].multi_path_skill_tree.append(talent);
|
||||
}
|
||||
}
|
||||
try rsp.multi_path_avatar_info_list.appendSlice(&multis);
|
||||
try rsp.basic_type_id_list.appendSlice(&Data.MultiAvatar);
|
||||
try rsp.cur_multi_path_avatar_type_map.append(.{ .key = 1001, .value = .Mar_7thKnightType });
|
||||
try rsp.cur_multi_path_avatar_type_map.append(.{ .key = 8001, .value = .GirlMemoryType });
|
||||
rsp.retcode = 0;
|
||||
|
||||
return rsp;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn UidGenerator() type {
|
||||
return struct {
|
||||
current_id: u32,
|
||||
const Self = @This();
|
||||
pub fn init(initial_id: u32) Self {
|
||||
return Self{ .current_id = initial_id };
|
||||
}
|
||||
pub fn nextId(self: *Self) u32 {
|
||||
self.current_id +%= 1;
|
||||
return self.current_id;
|
||||
}
|
||||
};
|
||||
}
|
289
gameserver/src/manager/scene_mgr.zig
Normal file
289
gameserver/src/manager/scene_mgr.zig
Normal file
|
@ -0,0 +1,289 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("../services/config.zig");
|
||||
const Res_config = @import("../services/res_config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
|
||||
const UidGenerator = @import("../services/item.zig").UidGenerator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub const SceneManager = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) SceneManager {
|
||||
return SceneManager{ .allocator = allocator };
|
||||
}
|
||||
|
||||
pub fn createScene(
|
||||
self: *SceneManager,
|
||||
plane_id: u32,
|
||||
floor_id: u32,
|
||||
entry_id: u32,
|
||||
teleport_id: u32,
|
||||
) !protocol.SceneInfo {
|
||||
const config = try Config.loadGameConfig(self.allocator, "config.json");
|
||||
const res_config = try Res_config.anchorLoader(self.allocator, "resources/res.json");
|
||||
var generator = UidGenerator().init();
|
||||
var scene_info = protocol.SceneInfo.init(self.allocator);
|
||||
scene_info.game_mode_type = 1;
|
||||
scene_info.plane_id = plane_id;
|
||||
scene_info.floor_id = floor_id;
|
||||
scene_info.entry_id = entry_id;
|
||||
scene_info.leader_entity_id = 100000;
|
||||
scene_info.world_id = 501;
|
||||
scene_info.client_pos_version = 1;
|
||||
var group_map = std.AutoHashMap(u32, protocol.SceneEntityGroupInfo).init(self.allocator);
|
||||
defer group_map.deinit();
|
||||
|
||||
for (res_config.scene_config.items) |sceneConf| {
|
||||
for (sceneConf.teleports.items) |teleConf| {
|
||||
if (teleConf.teleportId == teleport_id) {
|
||||
var scene_group = protocol.SceneEntityGroupInfo.init(self.allocator);
|
||||
scene_group.state = 1;
|
||||
for (config.avatar_config.items, 0..) |avatarConf, idx| {
|
||||
try scene_group.entity_list.append(.{
|
||||
.InstId = 1,
|
||||
.EntityId = @intCast(idx + 100000),
|
||||
.entityCase_ = .{ .Actor = .{
|
||||
.base_avatar_id = avatarConf.id,
|
||||
.avatar_type = .AVATAR_FORMAL_TYPE,
|
||||
.uid = 0,
|
||||
.map_layer = 0,
|
||||
} },
|
||||
.Motion = .{
|
||||
.pos = .{ .x = teleConf.pos.x, .y = teleConf.pos.y, .z = teleConf.pos.z },
|
||||
.rot = .{ .x = teleConf.rot.x, .y = teleConf.rot.y, .z = teleConf.rot.z },
|
||||
},
|
||||
});
|
||||
}
|
||||
try scene_info.entity_group_list.append(scene_group);
|
||||
}
|
||||
}
|
||||
if (scene_info.plane_id != 10000 and scene_info.plane_id != 10202 and sceneConf.planeID == scene_info.plane_id) {
|
||||
for (sceneConf.props.items) |propConf| {
|
||||
var scene_group = try getOrCreateGroup(&group_map, propConf.groupId, self.allocator);
|
||||
var prop_info = protocol.ScenePropInfo.init(self.allocator);
|
||||
prop_info.prop_id = propConf.propId;
|
||||
prop_info.prop_state = propConf.propState;
|
||||
try scene_group.entity_list.append(.{
|
||||
.entityCase_ = .{ .Prop = prop_info },
|
||||
.GroupId = scene_group.group_id,
|
||||
.InstId = propConf.instId,
|
||||
.EntityId = generator.nextId(),
|
||||
.Motion = .{
|
||||
.pos = .{ .x = propConf.pos.x, .y = propConf.pos.y, .z = propConf.pos.z },
|
||||
.rot = .{ .x = propConf.rot.x, .y = propConf.rot.y, .z = propConf.rot.z },
|
||||
},
|
||||
});
|
||||
}
|
||||
for (sceneConf.monsters.items) |monsConf| {
|
||||
var scene_group = try getOrCreateGroup(&group_map, monsConf.groupId, self.allocator);
|
||||
var monster_info = protocol.SceneNpcMonsterInfo.init(self.allocator);
|
||||
monster_info.monster_id = monsConf.monsterId;
|
||||
monster_info.event_id = monsConf.eventId;
|
||||
monster_info.world_level = 6;
|
||||
try scene_group.entity_list.append(.{
|
||||
.entityCase_ = .{ .NpcMonster = monster_info },
|
||||
.GroupId = scene_group.group_id,
|
||||
.InstId = monsConf.instId,
|
||||
.EntityId = generator.nextId(),
|
||||
.Motion = .{
|
||||
.pos = .{ .x = monsConf.pos.x, .y = monsConf.pos.y, .z = monsConf.pos.z },
|
||||
.rot = .{ .x = monsConf.rot.x, .y = monsConf.rot.y, .z = monsConf.rot.z },
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
var iter = group_map.iterator();
|
||||
while (iter.next()) |entry| {
|
||||
try scene_info.entity_group_list.append(entry.value_ptr.*);
|
||||
try scene_info.entity_list.appendSlice(entry.value_ptr.entity_list.items);
|
||||
try scene_info.DJBIBIJMEBH.append(entry.value_ptr.group_id);
|
||||
try scene_info.custom_data_list.append(protocol.CustomSaveData{
|
||||
.group_id = entry.value_ptr.group_id,
|
||||
});
|
||||
try scene_info.group_state_list.append(protocol.SceneGroupState{
|
||||
.group_id = entry.value_ptr.group_id,
|
||||
.state = 0,
|
||||
.is_default = true,
|
||||
});
|
||||
}
|
||||
const ranges = [_][2]usize{
|
||||
.{ 0, 101 },
|
||||
.{ 10000, 10051 },
|
||||
.{ 20000, 20001 },
|
||||
.{ 30000, 30020 },
|
||||
};
|
||||
for (ranges) |range| {
|
||||
for (range[0]..range[1]) |i| {
|
||||
try scene_info.lighten_section_list.append(@intCast(i));
|
||||
}
|
||||
}
|
||||
return scene_info;
|
||||
}
|
||||
fn getOrCreateGroup(group_map: *std.AutoHashMap(u32, protocol.SceneEntityGroupInfo), group_id: u32, allocator: std.mem.Allocator) !*protocol.SceneEntityGroupInfo {
|
||||
if (group_map.getPtr(group_id)) |existing_group| {
|
||||
return existing_group;
|
||||
}
|
||||
var new_group = protocol.SceneEntityGroupInfo.init(allocator);
|
||||
new_group.state = 1;
|
||||
new_group.group_id = group_id;
|
||||
try group_map.put(group_id, new_group);
|
||||
return group_map.getPtr(group_id).?;
|
||||
}
|
||||
};
|
||||
pub const ChallengeSceneManager = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
pub fn init(allocator: std.mem.Allocator) ChallengeSceneManager {
|
||||
return ChallengeSceneManager{ .allocator = allocator };
|
||||
}
|
||||
pub fn createScene(
|
||||
self: *ChallengeSceneManager,
|
||||
avatar_list: ArrayList(u32),
|
||||
plane_id: u32,
|
||||
floor_id: u32,
|
||||
entry_id: u32,
|
||||
world_id: u32,
|
||||
monster_id: u32,
|
||||
event_id: u32,
|
||||
group_id: u32,
|
||||
maze_group_id: u32,
|
||||
) !protocol.SceneInfo {
|
||||
const res_config = try Res_config.anchorLoader(self.allocator, "resources/res.json");
|
||||
var generator = UidGenerator().init();
|
||||
|
||||
var scene_info = protocol.SceneInfo.init(self.allocator);
|
||||
scene_info.game_mode_type = 4;
|
||||
scene_info.plane_id = plane_id;
|
||||
scene_info.floor_id = floor_id;
|
||||
scene_info.entry_id = entry_id;
|
||||
scene_info.leader_entity_id = 1;
|
||||
scene_info.world_id = world_id;
|
||||
try scene_info.group_state_list.append(protocol.SceneGroupState{
|
||||
.group_id = maze_group_id,
|
||||
.is_default = true,
|
||||
});
|
||||
{ // Character
|
||||
var scene_group = protocol.SceneEntityGroupInfo.init(self.allocator);
|
||||
scene_group.state = 1;
|
||||
scene_group.group_id = 0;
|
||||
for (avatar_list.items, 0..) |avatarConf, idx| {
|
||||
const newidx = idx + 100000;
|
||||
try scene_group.entity_list.append(.{
|
||||
.InstId = 1,
|
||||
.EntityId = @intCast(newidx),
|
||||
.entityCase_ = .{
|
||||
.Actor = .{
|
||||
.base_avatar_id = avatarConf,
|
||||
.avatar_type = .AVATAR_FORMAL_TYPE,
|
||||
.uid = 1,
|
||||
.map_layer = 0,
|
||||
},
|
||||
},
|
||||
.Motion = .{ .pos = .{}, .rot = .{} },
|
||||
});
|
||||
}
|
||||
try scene_info.entity_group_list.append(scene_group);
|
||||
}
|
||||
for (res_config.scene_config.items) |sceneConf| {
|
||||
if (sceneConf.planeID == scene_info.plane_id) {
|
||||
for (sceneConf.monsters.items) |monsConf| { //create monster
|
||||
var scene_group = protocol.SceneEntityGroupInfo.init(self.allocator);
|
||||
scene_group.state = 1;
|
||||
if (monsConf.groupId == group_id) {
|
||||
scene_group.group_id = group_id;
|
||||
|
||||
var monster_info = protocol.SceneNpcMonsterInfo.init(self.allocator);
|
||||
monster_info.monster_id = monster_id;
|
||||
monster_info.event_id = event_id;
|
||||
monster_info.world_level = 6;
|
||||
|
||||
try scene_group.entity_list.append(.{
|
||||
.entityCase_ = .{ .NpcMonster = monster_info },
|
||||
.GroupId = group_id,
|
||||
.InstId = monsConf.instId,
|
||||
.EntityId = generator.nextId(),
|
||||
.Motion = .{
|
||||
.pos = .{ .x = monsConf.pos.x, .y = monsConf.pos.y, .z = monsConf.pos.z },
|
||||
.rot = .{ .x = monsConf.rot.x, .y = monsConf.rot.y, .z = monsConf.rot.z },
|
||||
},
|
||||
});
|
||||
try scene_info.entity_group_list.append(scene_group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (res_config.scene_config.items) |sceneConf| {
|
||||
if (sceneConf.planeID == scene_info.plane_id) {
|
||||
for (sceneConf.props.items) |propConf| { //create props
|
||||
var scene_group = protocol.SceneEntityGroupInfo.init(self.allocator);
|
||||
scene_group.state = 1;
|
||||
scene_group.group_id = group_id;
|
||||
|
||||
var prop_info = protocol.ScenePropInfo.init(self.allocator);
|
||||
prop_info.prop_id = propConf.propId;
|
||||
prop_info.prop_state = propConf.propState;
|
||||
|
||||
try scene_group.entity_list.append(.{
|
||||
.entityCase_ = .{ .Prop = prop_info },
|
||||
.GroupId = group_id,
|
||||
.InstId = propConf.instId,
|
||||
.EntityId = 0,
|
||||
.Motion = .{
|
||||
.pos = .{ .x = propConf.pos.x, .y = propConf.pos.y, .z = propConf.pos.z },
|
||||
.rot = .{ .x = propConf.rot.x, .y = propConf.rot.y, .z = propConf.rot.z },
|
||||
},
|
||||
});
|
||||
try scene_info.entity_group_list.append(scene_group);
|
||||
}
|
||||
}
|
||||
}
|
||||
return scene_info;
|
||||
}
|
||||
};
|
||||
|
||||
pub const MazeMapManager = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
pub fn init(allocator: std.mem.Allocator) MazeMapManager {
|
||||
return MazeMapManager{ .allocator = allocator };
|
||||
}
|
||||
pub fn setMazeMapData(
|
||||
self: *MazeMapManager,
|
||||
map_info: *protocol.SceneMapInfo,
|
||||
floor_id: u32,
|
||||
) !void {
|
||||
const config = try Config.loadMapEntranceConfig(self.allocator, "resources/MapEntrance.json");
|
||||
const res_config = try Res_config.anchorLoader(self.allocator, "resources/res.json");
|
||||
var plane_ids = ArrayList(u32).init(self.allocator);
|
||||
for (config.map_entrance_config.items) |entrConf| {
|
||||
if (entrConf.floor_id == floor_id) {
|
||||
try plane_ids.append(entrConf.plane_id);
|
||||
}
|
||||
}
|
||||
|
||||
map_info.maze_group_list = ArrayList(protocol.MazeGroup).init(self.allocator);
|
||||
map_info.maze_prop_list = ArrayList(protocol.MazePropState).init(self.allocator);
|
||||
for (res_config.scene_config.items) |resConf| {
|
||||
for (plane_ids.items) |plane_id| {
|
||||
if (resConf.planeID == plane_id) {
|
||||
for (resConf.props.items) |propConf| {
|
||||
try map_info.maze_group_list.append(protocol.MazeGroup{
|
||||
.NOBKEONAKLE = ArrayList(u32).init(self.allocator),
|
||||
.group_id = propConf.groupId,
|
||||
});
|
||||
try map_info.maze_prop_list.append(protocol.MazePropState{
|
||||
.group_id = propConf.groupId,
|
||||
.config_id = propConf.instId,
|
||||
.state = propConf.propState,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
42
gameserver/src/network.zig
Normal file
42
gameserver/src/network.zig
Normal file
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
const Session = @import("Session.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub fn listen() !void {
|
||||
const addr = std.net.Address.parseIp4("0.0.0.0", 23301) catch unreachable;
|
||||
var listener = try addr.listen(.{
|
||||
.kernel_backlog = 100,
|
||||
.reuse_address = true,
|
||||
});
|
||||
|
||||
std.log.info("server is listening at {}", .{listener.listen_address});
|
||||
|
||||
while (true) {
|
||||
const conn = listener.accept() catch continue;
|
||||
errdefer conn.stream.close();
|
||||
|
||||
const thread = try std.Thread.spawn(.{}, runSession, .{ conn.address, conn.stream });
|
||||
thread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
fn runSession(address: std.net.Address, stream: std.net.Stream) !void {
|
||||
std.log.info("new connection from {}", .{address});
|
||||
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer if (gpa.deinit() == .leak) std.log.err("memory leaks were detected for session at {}", .{address});
|
||||
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
const session = try allocator.create(Session);
|
||||
session.* = Session.init(address, stream, allocator);
|
||||
|
||||
if (session.*.run()) |_| {
|
||||
std.log.info("client from {} disconnected", .{address});
|
||||
} else |err| {
|
||||
std.log.err("session disconnected with an error: {}", .{err});
|
||||
}
|
||||
|
||||
allocator.destroy(session);
|
||||
}
|
284
gameserver/src/services/avatar.zig
Normal file
284
gameserver/src/services/avatar.zig
Normal file
|
@ -0,0 +1,284 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
|
||||
const UidGenerator = @import("item.zig").UidGenerator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub var m7th: bool = true;
|
||||
pub var mg: bool = true;
|
||||
pub var mac: u32 = 4;
|
||||
|
||||
// function to check the list if true
|
||||
fn isInList(id: u32, list: []const u32) bool {
|
||||
for (list) |item| {
|
||||
if (item == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
fn MultiPathUidGenerator() type {
|
||||
return struct {
|
||||
current_id: u32,
|
||||
const Self = @This();
|
||||
pub fn init(initial_id: u32) Self {
|
||||
return Self{ .current_id = initial_id };
|
||||
}
|
||||
pub fn nextId(self: *Self) u32 {
|
||||
self.current_id +%= 1;
|
||||
return self.current_id;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn onGetAvatarData(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const config = try Config.loadGameConfig(allocator, "config.json");
|
||||
var generator = UidGenerator().init();
|
||||
const req = try packet.getProto(protocol.GetAvatarDataCsReq, allocator);
|
||||
var rsp = protocol.GetAvatarDataScRsp.init(allocator);
|
||||
const GeneratorType = MultiPathUidGenerator();
|
||||
const avatar_ids = [_][]const u32{
|
||||
&[_]u32{ 8001, 8002 },
|
||||
&[_]u32{ 8003, 8004 },
|
||||
&[_]u32{ 8005, 8006 },
|
||||
&[_]u32{ 8007, 8008 },
|
||||
&[_]u32{1001},
|
||||
&[_]u32{1224},
|
||||
};
|
||||
const avatar_types = [_]protocol.MultiPathAvatarType{
|
||||
.GirlWarriorType, .GirlKnightType, .GirlShamanType,
|
||||
.GirlMemoryType, .Mar_7thKnightType, .Mar_7thRogueType,
|
||||
};
|
||||
var indexes: [6]u32 = [_]u32{0} ** 6;
|
||||
var counts: [6]u32 = [_]u32{0} ** 6;
|
||||
var multis: [6]protocol.MultiPathAvatarInfo = undefined;
|
||||
for (&multis, avatar_types, 0..) |*multi, avatar_type, i| {
|
||||
std.debug.print("MULTIPATH AVATAR INDEX: {} IS {}\n", .{ i, avatar_type });
|
||||
multi.* = protocol.MultiPathAvatarInfo.init(allocator);
|
||||
multi.avatar_id = avatar_type;
|
||||
if (avatar_type == .Mar_7thKnightType) {
|
||||
multi.dressed_skin_id = 1100101;
|
||||
}
|
||||
}
|
||||
for (config.avatar_config.items) |avatar| {
|
||||
for (0..avatar_ids.len) |i| {
|
||||
counts[i] += 1;
|
||||
for (avatar_ids[i]) |id| {
|
||||
if (avatar.id == id) {
|
||||
multis[i].rank = avatar.rank;
|
||||
indexes[i] = counts[i] - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var generators: [6]GeneratorType = undefined;
|
||||
for (0..multis.len) |i| {
|
||||
generators[i] = GeneratorType.init(indexes[i] * 7 + 1);
|
||||
}
|
||||
for (0..multis.len) |i| {
|
||||
var multi = &multis[i];
|
||||
var gen = &generators[i];
|
||||
|
||||
multi.path_equipment_id = indexes[i] * 7 + 1;
|
||||
multi.equip_relic_list = ArrayList(protocol.EquipRelic).init(allocator);
|
||||
|
||||
for (0..6) |slot| {
|
||||
try multi.equip_relic_list.append(.{
|
||||
.relic_unique_id = gen.nextId(),
|
||||
.type = @intCast(slot),
|
||||
});
|
||||
}
|
||||
}
|
||||
for (0..multis.len) |i| {
|
||||
const skill_set = if (i == 3) &Data.skills else &Data.skills_old;
|
||||
for (skill_set) |skill| {
|
||||
const talent_level: u32 = if (skill == 1 or skill == 301 or skill == 302) 6 else if (skill <= 4) 10 else 1;
|
||||
const point_id = if (avatar_ids[i].len > 1)
|
||||
avatar_ids[i][1] * 1000 + skill
|
||||
else
|
||||
avatar_ids[i][0] * 1000 + skill;
|
||||
const talent = protocol.AvatarSkillTree{
|
||||
.point_id = point_id,
|
||||
.level = talent_level,
|
||||
};
|
||||
try multis[i].multi_path_skill_tree.append(talent);
|
||||
}
|
||||
}
|
||||
try rsp.multi_path_avatar_info_list.appendSlice(&multis);
|
||||
try rsp.basic_type_id_list.appendSlice(&Data.MultiAvatar);
|
||||
try rsp.cur_multi_path_avatar_type_map.append(.{ .key = 1001, .value = .Mar_7thKnightType });
|
||||
try rsp.cur_multi_path_avatar_type_map.append(.{ .key = 8001, .value = .GirlMemoryType });
|
||||
|
||||
rsp.is_get_all = req.is_get_all;
|
||||
for (Data.AllAvatars) |id| {
|
||||
var avatar = protocol.Avatar.init(allocator);
|
||||
avatar.base_avatar_id = id;
|
||||
avatar.level = 80;
|
||||
avatar.promotion = 6;
|
||||
avatar.rank = 6;
|
||||
avatar.has_taken_promotion_reward_list = ArrayList(u32).init(allocator);
|
||||
for (1..6) |i| {
|
||||
try avatar.has_taken_promotion_reward_list.append(@intCast(i));
|
||||
}
|
||||
|
||||
var talentLevel: u32 = 0;
|
||||
const skill_list: []const u32 = if (isInList(avatar.base_avatar_id, &Data.Rem)) &Data.skills else &Data.skills_old;
|
||||
for (skill_list) |elem| {
|
||||
talentLevel = switch (elem) {
|
||||
1 => 6,
|
||||
2...4 => 10,
|
||||
301, 302 => if (isInList(avatar.base_avatar_id, &Data.Rem)) 6 else 1,
|
||||
else => 1,
|
||||
};
|
||||
const talent = protocol.AvatarSkillTree{ .point_id = avatar.base_avatar_id * 1000 + elem, .level = talentLevel };
|
||||
try avatar.skilltree_list.append(talent);
|
||||
}
|
||||
try rsp.avatar_list.append(avatar);
|
||||
}
|
||||
for (config.avatar_config.items) |avatarConf| {
|
||||
var avatar = protocol.Avatar.init(allocator);
|
||||
avatar.base_avatar_id = switch (avatarConf.id) {
|
||||
8001...8008 => 8001,
|
||||
1224 => 1001,
|
||||
else => avatarConf.id,
|
||||
};
|
||||
avatar.level = avatarConf.level;
|
||||
avatar.promotion = avatarConf.promotion;
|
||||
avatar.rank = avatarConf.rank;
|
||||
|
||||
if (isInList(avatar.base_avatar_id, &Data.EnhanceAvatarID)) {
|
||||
avatar.NDEFNACPCLH = 1;
|
||||
}
|
||||
avatar.has_taken_promotion_reward_list = ArrayList(u32).init(allocator);
|
||||
for (1..6) |i| {
|
||||
try avatar.has_taken_promotion_reward_list.append(@intCast(i));
|
||||
}
|
||||
avatar.equipment_unique_id = generator.nextId();
|
||||
avatar.equip_relic_list = ArrayList(protocol.EquipRelic).init(allocator);
|
||||
for (0..6) |i| {
|
||||
try avatar.equip_relic_list.append(.{
|
||||
.relic_unique_id = generator.nextId(), // uid
|
||||
.type = @intCast(i), // slot
|
||||
});
|
||||
}
|
||||
var talentLevel: u32 = 0;
|
||||
const skill_list: []const u32 = if (isInList(avatar.base_avatar_id, &Data.Rem)) &Data.skills else &Data.skills_old;
|
||||
for (skill_list) |elem| {
|
||||
talentLevel = switch (elem) {
|
||||
1 => 6,
|
||||
2...4 => 10,
|
||||
301, 302 => if (isInList(avatar.base_avatar_id, &Data.Rem)) 6 else 1,
|
||||
else => 1,
|
||||
};
|
||||
var point_id: u32 = 0;
|
||||
if (isInList(avatar.base_avatar_id, &Data.EnhanceAvatarID)) point_id = avatar.base_avatar_id + 10000 else point_id = avatar.base_avatar_id;
|
||||
const talent = protocol.AvatarSkillTree{ .point_id = point_id * 1000 + elem, .level = talentLevel };
|
||||
try avatar.skilltree_list.append(talent);
|
||||
}
|
||||
try rsp.avatar_list.append(avatar);
|
||||
const avatarType: protocol.MultiPathAvatarType = @enumFromInt(avatarConf.id);
|
||||
if (@intFromEnum(avatarType) > 1) {
|
||||
try session.send(CmdID.CmdSetAvatarPathScRsp, protocol.SetAvatarPathScRsp{
|
||||
.retcode = 0,
|
||||
.avatar_id = avatarType,
|
||||
});
|
||||
}
|
||||
}
|
||||
try session.send(CmdID.CmdGetAvatarDataScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onGetBasicInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetBasicInfoScRsp.init(allocator);
|
||||
rsp.Gender = 2;
|
||||
rsp.IsGenderSet = true;
|
||||
rsp.PlayerSettingInfo = .{};
|
||||
try session.send(CmdID.CmdGetBasicInfoScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onSetAvatarPath(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.SetAvatarPathScRsp.init(allocator);
|
||||
|
||||
const req = try packet.getProto(protocol.SetAvatarPathCsReq, allocator);
|
||||
rsp.avatar_id = req.avatar_id;
|
||||
if (rsp.avatar_id == protocol.MultiPathAvatarType.Mar_7thKnightType) {
|
||||
m7th = false;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.Mar_7thRogueType) {
|
||||
m7th = true;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.BoyWarriorType) {
|
||||
mac = 1;
|
||||
mg = false;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.BoyKnightType) {
|
||||
mac = 2;
|
||||
mg = false;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.BoyShamanType) {
|
||||
mac = 3;
|
||||
mg = false;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.BoyMemoryType) {
|
||||
mac = 4;
|
||||
mg = false;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.GirlWarriorType) {
|
||||
mac = 1;
|
||||
mg = true;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.GirlKnightType) {
|
||||
mac = 2;
|
||||
mg = true;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.GirlShamanType) {
|
||||
mac = 3;
|
||||
mg = true;
|
||||
} else if (rsp.avatar_id == protocol.MultiPathAvatarType.GirlMemoryType) {
|
||||
mac = 4;
|
||||
mg = true;
|
||||
}
|
||||
|
||||
var sync = protocol.AvatarPathChangedNotify.init(allocator);
|
||||
|
||||
if (req.avatar_id == protocol.MultiPathAvatarType.GirlMemoryType) {
|
||||
sync.base_avatar_id = 8008;
|
||||
} else if (req.avatar_id == protocol.MultiPathAvatarType.GirlShamanType) {
|
||||
sync.base_avatar_id = 8006;
|
||||
} else if (req.avatar_id == protocol.MultiPathAvatarType.GirlKnightType) {
|
||||
sync.base_avatar_id = 8004;
|
||||
} else if (req.avatar_id == protocol.MultiPathAvatarType.GirlWarriorType) {
|
||||
sync.base_avatar_id = 8002;
|
||||
}
|
||||
sync.cur_multi_path_avatar_type = req.avatar_id;
|
||||
|
||||
try session.send(CmdID.CmdAvatarPathChangedNotify, sync);
|
||||
try session.send(CmdID.CmdSetAvatarPathScRsp, rsp);
|
||||
}
|
||||
pub fn onDressAvatarSkin(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.DressAvatarSkinScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdDressAvatarSkinScRsp, rsp);
|
||||
}
|
||||
pub fn onTakeOffAvatarSkin(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.TakeOffAvatarSkinScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdTakeOffAvatarSkinScRsp, rsp);
|
||||
}
|
||||
pub fn onGetBigDataAll(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.GetBigDataAllRecommendCsReq, allocator);
|
||||
var rsp = protocol.GetBigDataAllRecommendScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.IANNEEIJAKH = req.IANNEEIJAKH;
|
||||
try session.send(CmdID.CmdGetBigDataAllRecommendScRsp, rsp);
|
||||
}
|
||||
pub fn onGetBigData(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.GetBigDataRecommendCsReq, allocator);
|
||||
var rsp = protocol.GetBigDataRecommendScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.IANNEEIJAKH = req.IANNEEIJAKH;
|
||||
rsp.EIGPMIBCIKG = req.EIGPMIBCIKG;
|
||||
try session.send(CmdID.CmdGetBigDataRecommendScRsp, rsp);
|
||||
}
|
||||
pub fn onGetPreAvatarGrowthInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetPreAvatarGrowthInfoScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdGetPreAvatarGrowthInfoScRsp, rsp);
|
||||
}
|
138
gameserver/src/services/battle.zig
Normal file
138
gameserver/src/services/battle.zig
Normal file
|
@ -0,0 +1,138 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const ChallengeData = @import("challenge.zig");
|
||||
const BattleManager = @import("../manager/battle_mgr.zig").BattleManager;
|
||||
const ChallegeStageManager = @import("../manager/battle_mgr.zig").ChallegeStageManager;
|
||||
const NodeCheck = @import("../commands/value.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub var on_battle: bool = false;
|
||||
|
||||
pub fn onStartCocoonStage(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.StartCocoonStageCsReq, allocator);
|
||||
var battle_mgr = BattleManager.init(allocator);
|
||||
const battle = try battle_mgr.createBattle();
|
||||
on_battle = true;
|
||||
try session.send(CmdID.CmdStartCocoonStageScRsp, protocol.StartCocoonStageScRsp{
|
||||
.retcode = 0,
|
||||
.cocoon_id = req.cocoon_id,
|
||||
.prop_entity_id = req.prop_entity_id,
|
||||
.wave = req.wave,
|
||||
.battle_info = battle,
|
||||
});
|
||||
}
|
||||
pub fn onQuickStartCocoonStage(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.QuickStartCocoonStageCsReq, allocator);
|
||||
var battle_mgr = BattleManager.init(allocator);
|
||||
const battle = try battle_mgr.createBattle();
|
||||
on_battle = true;
|
||||
try session.send(CmdID.CmdQuickStartCocoonStageScRsp, protocol.QuickStartCocoonStageScRsp{
|
||||
.retcode = 0,
|
||||
.cocoon_id = req.cocoon_id,
|
||||
.wave = req.wave,
|
||||
.battle_info = battle,
|
||||
});
|
||||
}
|
||||
pub fn onQuickStartFarmElement(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.QuickStartFarmElementCsReq, allocator);
|
||||
var battle_mgr = BattleManager.init(allocator);
|
||||
const battle = try battle_mgr.createBattle();
|
||||
on_battle = true;
|
||||
try session.send(CmdID.CmdQuickStartFarmElementScRsp, protocol.QuickStartFarmElementScRsp{
|
||||
.retcode = 0,
|
||||
.world_level = req.world_level,
|
||||
.JDANOKNHNHL = req.JDANOKNHNHL,
|
||||
.battle_info = battle,
|
||||
});
|
||||
}
|
||||
pub fn onStartBattleCollege(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.StartBattleCollegeCsReq, allocator);
|
||||
var battle_mgr = BattleManager.init(allocator);
|
||||
const battle = try battle_mgr.createBattle();
|
||||
on_battle = true;
|
||||
try session.send(CmdID.CmdStartBattleCollegeScRsp, protocol.StartBattleCollegeScRsp{
|
||||
.retcode = 0,
|
||||
.id = req.id,
|
||||
.battle_info = battle,
|
||||
});
|
||||
}
|
||||
pub fn onSceneCastSkill(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
var battle_mgr = BattleManager.init(allocator);
|
||||
const battle = try battle_mgr.createBattle();
|
||||
var challege_mgr = ChallegeStageManager.init(allocator);
|
||||
const challenge = try challege_mgr.createChallegeStage();
|
||||
const req = try packet.getProto(protocol.SceneCastSkillCsReq, allocator);
|
||||
var monster_battle_info_list = ArrayList(protocol.HitMonsterBattleInfo).init(allocator);
|
||||
try monster_battle_info_list.appendSlice(&[_]protocol.HitMonsterBattleInfo{
|
||||
.{
|
||||
.target_monster_entity_id = 0,
|
||||
.monster_battle_type = protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_TRIGGER_BATTLE,
|
||||
},
|
||||
});
|
||||
|
||||
var battle_info: ?protocol.SceneBattleInfo = null;
|
||||
|
||||
if (req.assist_monster_entity_id_list.items.len > 0 or
|
||||
(req.attacked_by_entity_id >= 1 and req.attacked_by_entity_id <= 99))
|
||||
{
|
||||
if (ChallengeData.on_challenge) {
|
||||
battle_info = challenge;
|
||||
} else {
|
||||
battle_info = battle;
|
||||
on_battle = true;
|
||||
}
|
||||
}
|
||||
|
||||
try session.send(CmdID.CmdSceneCastSkillScRsp, protocol.SceneCastSkillScRsp{
|
||||
.retcode = 0,
|
||||
.cast_entity_id = req.cast_entity_id,
|
||||
.monster_battle_info = monster_battle_info_list,
|
||||
.battle_info = battle_info,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn onGetCurBattleInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var battle_mgr = BattleManager.init(allocator);
|
||||
const battle = try battle_mgr.createBattle();
|
||||
var challege_mgr = ChallegeStageManager.init(allocator);
|
||||
const challenge = try challege_mgr.createChallegeStage();
|
||||
|
||||
var rsp = protocol.GetCurBattleInfoScRsp.init(allocator);
|
||||
rsp.battle_info = if (ChallengeData.on_challenge == true) challenge else if (on_battle == true) battle else null;
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdGetCurBattleInfoScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onPVEBattleResult(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.PVEBattleResultCsReq, allocator);
|
||||
var rsp = protocol.PVEBattleResultScRsp.init(allocator);
|
||||
rsp.battle_id = req.battle_id;
|
||||
rsp.end_status = req.end_status;
|
||||
rsp.stage_id = req.stage_id;
|
||||
on_battle = false;
|
||||
try session.send(CmdID.CmdPVEBattleResultScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onSceneCastSkillCostMp(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SceneCastSkillCostMpCsReq, allocator);
|
||||
try session.send(CmdID.CmdSceneCastSkillCostMpScRsp, protocol.SceneCastSkillCostMpScRsp{
|
||||
.retcode = 0,
|
||||
.cast_entity_id = req.cast_entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn onSyncClientResVersion(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SyncClientResVersionCsReq, allocator);
|
||||
std.debug.print("CLIENT RES VERSION: {}\n", .{req.client_res_version});
|
||||
try session.send(CmdID.CmdSyncClientResVersionScRsp, protocol.SyncClientResVersionScRsp{
|
||||
.retcode = 0,
|
||||
.client_res_version = req.client_res_version,
|
||||
});
|
||||
}
|
216
gameserver/src/services/challenge.zig
Normal file
216
gameserver/src/services/challenge.zig
Normal file
|
@ -0,0 +1,216 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("config.zig");
|
||||
const Res_config = @import("res_config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const ChallegeStageManager = @import("../manager/battle_mgr.zig").ChallegeStageManager;
|
||||
const ChallengeManager = @import("../manager/challenge_mgr.zig").ChallengeManager;
|
||||
const SceneManager = @import("../manager/scene_mgr.zig").SceneManager;
|
||||
const ChallengeSceneManager = @import("../manager/scene_mgr.zig").ChallengeSceneManager;
|
||||
const LineupManager = @import("../manager/lineup_mgr.zig").LineupManager;
|
||||
const ChallengeLineupManager = @import("../manager/lineup_mgr.zig").ChallengeLineupManager;
|
||||
const NodeCheck = @import("../commands/value.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub fn UidGenerator() type {
|
||||
return struct {
|
||||
current_id: u32,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init() Self {
|
||||
return Self{ .current_id = 100000 };
|
||||
}
|
||||
|
||||
pub fn nextId(self: *Self) u32 {
|
||||
self.current_id +%= 1; // Using wrapping addition
|
||||
return self.current_id;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn contains(list: *const std.ArrayListAligned(u32, null), value: u32) bool {
|
||||
for (list.items) |item| {
|
||||
if (item == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
pub var on_challenge: bool = false;
|
||||
|
||||
pub const ChallengeBlessing = ArrayList(u32);
|
||||
pub var challenge_blessing: []const u32 = &.{};
|
||||
pub var challenge_mode: u32 = 0;
|
||||
|
||||
pub var challenge_planeID: u32 = 0;
|
||||
pub var challenge_floorID: u32 = 0;
|
||||
pub var challenge_entryID: u32 = 0;
|
||||
pub var challenge_worldID: u32 = 0;
|
||||
pub var challenge_monsterID: u32 = 0;
|
||||
pub var challenge_eventID: u32 = 0;
|
||||
pub var challenge_groupID: u32 = 0;
|
||||
pub var challenge_maze_groupID: u32 = 0;
|
||||
pub var challenge_stageID: u32 = 0;
|
||||
|
||||
pub var challengeID: u32 = 0;
|
||||
pub var challenge_buffID: u32 = 0;
|
||||
|
||||
pub const ChallengeAvatarList = ArrayList(u32);
|
||||
pub var avatar_list: ChallengeAvatarList = ChallengeAvatarList.init(std.heap.page_allocator);
|
||||
|
||||
pub fn resetChallengeState() void {
|
||||
on_challenge = false;
|
||||
challenge_mode = 0;
|
||||
challenge_planeID = 0;
|
||||
challenge_floorID = 0;
|
||||
challenge_entryID = 0;
|
||||
challenge_worldID = 0;
|
||||
challenge_monsterID = 0;
|
||||
challenge_eventID = 0;
|
||||
challenge_groupID = 0;
|
||||
challenge_maze_groupID = 0;
|
||||
challenge_stageID = 0;
|
||||
challengeID = 0;
|
||||
challenge_buffID = 0;
|
||||
challenge_blessing = &.{};
|
||||
_ = avatar_list.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
pub fn onGetChallenge(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
const challenge_config = try Config.loadChallengeConfig(allocator, "resources/ChallengeMazeConfig.json");
|
||||
var rsp = protocol.GetChallengeScRsp.init(allocator);
|
||||
|
||||
rsp.retcode = 0;
|
||||
for (challenge_config.challenge_config.items) |ids| {
|
||||
var challenge = protocol.Challenge.init(allocator);
|
||||
challenge.challenge_id = ids.id;
|
||||
challenge.star = 1;
|
||||
if (ids.id > 20000 and ids.id < 30000) {
|
||||
challenge.score_id = 40000;
|
||||
challenge.score_two = 40000;
|
||||
}
|
||||
try rsp.challenge_list.append(challenge);
|
||||
}
|
||||
|
||||
try session.send(CmdID.CmdGetChallengeScRsp, rsp);
|
||||
}
|
||||
pub fn onGetChallengeGroupStatistics(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.GetChallengeGroupStatisticsCsReq, allocator);
|
||||
var rsp = protocol.GetChallengeGroupStatisticsScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.group_id = req.group_id;
|
||||
try session.send(CmdID.CmdGetChallengeGroupStatisticsScRsp, rsp);
|
||||
}
|
||||
pub fn onLeaveChallenge(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var lineup_mgr = LineupManager.init(allocator);
|
||||
const lineup = try lineup_mgr.createLineup();
|
||||
var scene_manager = SceneManager.init(allocator);
|
||||
const scene_info = try scene_manager.createScene(20432, 20432001, 2043201, 1213);
|
||||
try session.send(CmdID.CmdQuitBattleScNotify, protocol.QuitBattleScNotify{});
|
||||
try session.send(CmdID.CmdEnterSceneByServerScNotify, protocol.EnterSceneByServerScNotify{
|
||||
.reason = protocol.EnterSceneReason.ENTER_SCENE_REASON_NONE,
|
||||
.lineup = lineup,
|
||||
.scene = scene_info,
|
||||
});
|
||||
resetChallengeState();
|
||||
challenge_mode = 0;
|
||||
try session.send(CmdID.CmdLeaveChallengeScRsp, protocol.LeaveChallengeScRsp{
|
||||
.retcode = 0,
|
||||
});
|
||||
}
|
||||
pub fn onGetCurChallengeScRsp(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetCurChallengeScRsp.init(allocator);
|
||||
var lineup_manager = ChallengeLineupManager.init(allocator);
|
||||
const lineup_info = try lineup_manager.createLineup(avatar_list);
|
||||
var challenge_manager = ChallengeManager.init(allocator);
|
||||
const cur_challenge_info = try challenge_manager.createChallenge(
|
||||
challengeID,
|
||||
challenge_buffID,
|
||||
);
|
||||
rsp.retcode = 0;
|
||||
if (on_challenge == true) {
|
||||
rsp.cur_challenge = cur_challenge_info;
|
||||
try rsp.lineup_list.append(lineup_info);
|
||||
|
||||
std.debug.print("CURRENT CHALLENGE STAGE ID:{}\n", .{challenge_stageID});
|
||||
std.debug.print("CURRENT CHALLENGE LINEUP AVATAR ID:{}\n", .{avatar_list});
|
||||
std.debug.print("CURRENT CHALLENGE MONSTER ID:{}\n", .{challenge_monsterID});
|
||||
if (challenge_mode == 0) {
|
||||
std.debug.print("CURRENT CHALLENGE: {} MOC\n", .{challenge_mode});
|
||||
} else if (challenge_mode == 1) {
|
||||
std.debug.print("CURRENT CHALLENGE: {} PF\n", .{challenge_mode});
|
||||
std.debug.print("CURRENT CHALLENGE STAGE BLESSING ID:{}, SELECTED BLESSING ID:{}\n", .{ challenge_blessing[0], challenge_blessing[1] });
|
||||
} else {
|
||||
std.debug.print("CURRENT CHALLENGE: {} AS\n", .{challenge_mode});
|
||||
std.debug.print("CURRENT CHALLENGE STAGE BLESSING ID:{}, SELECTED BLESSING ID:{}\n", .{ challenge_blessing[0], challenge_blessing[1] });
|
||||
}
|
||||
} else {
|
||||
std.debug.print("CURRENT ON CHALLENGE STATE: {}\n", .{on_challenge});
|
||||
}
|
||||
|
||||
try session.send(CmdID.CmdGetCurChallengeScRsp, rsp);
|
||||
}
|
||||
pub fn onStartChallenge(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.StartChallengeCsReq, allocator);
|
||||
var rsp = protocol.StartChallengeScRsp.init(allocator);
|
||||
|
||||
challengeID = req.challenge_id;
|
||||
|
||||
if (NodeCheck.challenge_node == 0) {
|
||||
for (req.first_lineup.items) |id| {
|
||||
try avatar_list.append(id);
|
||||
}
|
||||
if (challengeID > 20000 and challengeID < 30000)
|
||||
challenge_buffID = req.stage_info.?.IEICDGGELNE.?.story_info.buff_one;
|
||||
if (challengeID > 30000)
|
||||
challenge_buffID = req.stage_info.?.IEICDGGELNE.?.boss_info.buff_one;
|
||||
} else {
|
||||
for (req.second_lineup.items) |id| {
|
||||
try avatar_list.append(id);
|
||||
}
|
||||
if (challengeID > 20000 and challengeID < 30000)
|
||||
challenge_buffID = req.stage_info.?.IEICDGGELNE.?.story_info.buff_two;
|
||||
if (challengeID > 30000)
|
||||
challenge_buffID = req.stage_info.?.IEICDGGELNE.?.boss_info.buff_two;
|
||||
}
|
||||
var lineup_manager = ChallengeLineupManager.init(allocator);
|
||||
const lineup_info = try lineup_manager.createLineup(avatar_list);
|
||||
|
||||
var challenge_manager = ChallengeManager.init(allocator);
|
||||
const cur_challenge_info = try challenge_manager.createChallenge(
|
||||
challengeID,
|
||||
challenge_buffID,
|
||||
);
|
||||
var scene_challenge_manager = ChallengeSceneManager.init(allocator);
|
||||
const scene_info = try scene_challenge_manager.createScene(
|
||||
avatar_list,
|
||||
challenge_planeID,
|
||||
challenge_floorID,
|
||||
challenge_entryID,
|
||||
challenge_worldID,
|
||||
challenge_monsterID,
|
||||
challenge_eventID,
|
||||
challenge_groupID,
|
||||
challenge_maze_groupID,
|
||||
);
|
||||
rsp.retcode = 0;
|
||||
rsp.scene = scene_info;
|
||||
rsp.cur_challenge = cur_challenge_info;
|
||||
try rsp.lineup_list.append(lineup_info);
|
||||
|
||||
on_challenge = true;
|
||||
try session.send(CmdID.CmdStartChallengeScRsp, rsp);
|
||||
std.debug.print("SEND PLANE ID {} FLOOR ID {} ENTRY ID {} GROUP ID {} MAZE GROUP ID {}\n", .{
|
||||
challenge_planeID,
|
||||
challenge_floorID,
|
||||
challenge_entryID,
|
||||
challenge_groupID,
|
||||
challenge_maze_groupID,
|
||||
});
|
||||
}
|
122
gameserver/src/services/chat.zig
Normal file
122
gameserver/src/services/chat.zig
Normal file
|
@ -0,0 +1,122 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const commandhandler = @import("../command.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
const B64Decoder = std.base64.standard.Decoder;
|
||||
|
||||
const EmojiList = [_]u32{};
|
||||
|
||||
pub fn onGetFriendListInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetFriendListInfoScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
|
||||
var assist_list = ArrayList(protocol.AssistSimpleInfo).init(allocator);
|
||||
try assist_list.appendSlice(&[_]protocol.AssistSimpleInfo{
|
||||
.{ .Pos = 0, .Level = 80, .avatar_id = 1403, .DressedSkinId = 0 },
|
||||
.{ .Pos = 1, .Level = 80, .avatar_id = 1407, .DressedSkinId = 0 },
|
||||
.{ .Pos = 2, .Level = 80, .avatar_id = 1001, .DressedSkinId = 1100101 },
|
||||
});
|
||||
|
||||
var friend = protocol.FriendSimpleInfo.init(allocator);
|
||||
friend.playing_state = .PLAYING_CHALLENGE_BOSS;
|
||||
friend.create_time = 0; //timestamp
|
||||
friend.remark_name = .{ .Const = "ReversedRooms" }; //friend_custom_nickname
|
||||
friend.is_marked = true;
|
||||
friend.player_simple_info = protocol.PlayerSimpleInfo{
|
||||
.signature = .{ .Const = "https://discord.gg/reversedrooms" },
|
||||
.nickname = .{ .Const = "JingliuSR" },
|
||||
.level = 70,
|
||||
.uid = 2000,
|
||||
.head_icon = 200140,
|
||||
.ANPLLAOBFJI = 253000,
|
||||
.chat_bubble_id = 220008,
|
||||
.assist_simple_info = assist_list,
|
||||
.platform_type = protocol.PlatformType.ANDROID,
|
||||
.online_status = protocol.FriendOnlineStatus.FRIEND_ONLINE_STATUS_ONLINE,
|
||||
};
|
||||
try rsp.friend_list.append(friend);
|
||||
try session.send(CmdID.CmdGetFriendListInfoScRsp, rsp);
|
||||
}
|
||||
pub fn onChatEmojiList(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetChatEmojiListScRsp.init(allocator);
|
||||
|
||||
rsp.retcode = 0;
|
||||
try rsp.chat_emoji_list.appendSlice(&EmojiList);
|
||||
|
||||
try session.send(CmdID.CmdGetChatEmojiListScRsp, rsp);
|
||||
}
|
||||
pub fn onPrivateChatHistory(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetPrivateChatHistoryScRsp.init(allocator);
|
||||
|
||||
rsp.retcode = 0;
|
||||
rsp.target_side = 1;
|
||||
rsp.contact_side = 2000;
|
||||
try rsp.chat_message_list.appendSlice(&[_]protocol.ChatMessageData{
|
||||
.{
|
||||
.content = .{ .Const = "/sync command is having some issues right now. In order to change gear setup, you need to re-login" },
|
||||
.message_type = .MSG_TYPE_CUSTOM_TEXT,
|
||||
.create_time = 0,
|
||||
.sender_id = 2000,
|
||||
},
|
||||
.{
|
||||
.content = .{ .Const = "/help for command list" },
|
||||
.message_type = .MSG_TYPE_CUSTOM_TEXT,
|
||||
.create_time = 0,
|
||||
.sender_id = 2000,
|
||||
},
|
||||
.{
|
||||
.content = .{ .Const = "to use command, use '/' first" },
|
||||
.message_type = .MSG_TYPE_CUSTOM_TEXT,
|
||||
.create_time = 0,
|
||||
.sender_id = 2000,
|
||||
},
|
||||
.{
|
||||
.extra_id = 122004,
|
||||
.message_type = .MSG_TYPE_EMOJI,
|
||||
.create_time = 0,
|
||||
.sender_id = 2000,
|
||||
},
|
||||
});
|
||||
|
||||
try session.send(CmdID.CmdGetPrivateChatHistoryScRsp, rsp);
|
||||
}
|
||||
pub fn onSendMsg(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
std.debug.print("Received packet: {any}\n", .{packet});
|
||||
const req = protocol.SendMsgCsReq.init(allocator);
|
||||
std.debug.print("Decoded request: {any}\n", .{req});
|
||||
std.debug.print("Raw packet body: {any}\n", .{packet.body});
|
||||
const msg_text = switch (req.message_text) {
|
||||
.Empty => "",
|
||||
.Owned => |owned| owned.str,
|
||||
.Const => |const_str| const_str,
|
||||
};
|
||||
var msg_text2: []const u8 = "";
|
||||
if (packet.body.len > 9 and packet.body[10] == 47) {
|
||||
msg_text2 = packet.body[10..packet.body.len];
|
||||
}
|
||||
std.debug.print("Manually extracted message text: '{s}'\n", .{msg_text2});
|
||||
|
||||
std.debug.print("Message Text 1: {any}\n", .{msg_text});
|
||||
|
||||
if (msg_text2.len > 0) {
|
||||
if (std.mem.indexOf(u8, msg_text2, "/") != null) {
|
||||
std.debug.print("Message contains a '/'\n", .{});
|
||||
try commandhandler.handleCommand(session, msg_text2, allocator);
|
||||
} else {
|
||||
std.debug.print("Message does not contain a '/'\n", .{});
|
||||
try commandhandler.sendMessage(session, msg_text2, allocator);
|
||||
}
|
||||
} else {
|
||||
std.debug.print("Empty message received\n", .{});
|
||||
}
|
||||
|
||||
var rsp = protocol.SendMsgScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdSendMsgScRsp, rsp);
|
||||
}
|
487
gameserver/src/services/config.zig
Normal file
487
gameserver/src/services/config.zig
Normal file
|
@ -0,0 +1,487 @@
|
|||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub const BattleConfig = struct {
|
||||
battle_id: u32,
|
||||
stage_id: u32,
|
||||
cycle_count: u32,
|
||||
monster_wave: ArrayList(ArrayList(u32)),
|
||||
monster_level: u32,
|
||||
blessings: ArrayList(u32),
|
||||
};
|
||||
pub const Stage = struct {
|
||||
level: u32,
|
||||
stage_id: u32,
|
||||
monster_list: ArrayList(ArrayList(u32)),
|
||||
};
|
||||
const ExtraMazeBuff = struct {
|
||||
enable: bool,
|
||||
mazebuff: ArrayList(u32),
|
||||
};
|
||||
|
||||
const Lightcone = struct {
|
||||
id: u32,
|
||||
rank: u32,
|
||||
level: u32,
|
||||
promotion: u32,
|
||||
};
|
||||
|
||||
pub const Relic = struct {
|
||||
id: u32,
|
||||
level: u32,
|
||||
main_affix_id: u32,
|
||||
sub_count: u32,
|
||||
stat1: u32,
|
||||
cnt1: u32,
|
||||
step1: u32,
|
||||
stat2: u32,
|
||||
cnt2: u32,
|
||||
step2: u32,
|
||||
stat3: u32,
|
||||
cnt3: u32,
|
||||
step3: u32,
|
||||
stat4: u32,
|
||||
cnt4: u32,
|
||||
step4: u32,
|
||||
};
|
||||
|
||||
pub const Avatar = struct {
|
||||
id: u32,
|
||||
hp: u32,
|
||||
sp: u32,
|
||||
level: u32,
|
||||
promotion: u32,
|
||||
rank: u32,
|
||||
lightcone: Lightcone,
|
||||
relics: ArrayList(Relic),
|
||||
use_technique: bool,
|
||||
};
|
||||
const PlayerIcon = struct {
|
||||
id: u32,
|
||||
};
|
||||
const MainMission = struct {
|
||||
main_mission_id: u32,
|
||||
};
|
||||
const TutorialGuide = struct {
|
||||
guide_group_id: u32,
|
||||
};
|
||||
const Tutorial = struct {
|
||||
tutorial_id: u32,
|
||||
};
|
||||
const Activity = struct {
|
||||
activity_module_list: ArrayList(u32),
|
||||
panel_id: u32,
|
||||
};
|
||||
const ChallengeConfig = struct {
|
||||
id: u32,
|
||||
npc_monster_id_list1: ArrayList(u32),
|
||||
npc_monster_id_list2: ArrayList(u32),
|
||||
event_id_list1: ArrayList(u32),
|
||||
event_id_list2: ArrayList(u32),
|
||||
map_entrance_id: u32,
|
||||
map_entrance_id2: u32,
|
||||
maze_group_id1: u32,
|
||||
maze_group_id2: ?u32, // to check if it missing MazeGroupID2 field
|
||||
maze_buff_id: u32,
|
||||
};
|
||||
|
||||
const MapEntrance = struct {
|
||||
floor_id: u32,
|
||||
id: u32,
|
||||
plane_id: u32,
|
||||
begin_main_mission_idlist: ArrayList(u32),
|
||||
finish_main_mission_idlist: ArrayList(u32),
|
||||
finish_sub_mission_idlist: ArrayList(u32),
|
||||
};
|
||||
const MazePlane = struct {
|
||||
floor_id_list: ArrayList(u32),
|
||||
start_floor_id: u32,
|
||||
challenge_plane_id: u32,
|
||||
world_id: u32,
|
||||
};
|
||||
pub const GameConfig = struct {
|
||||
battle_config: BattleConfig,
|
||||
avatar_config: ArrayList(Avatar),
|
||||
};
|
||||
pub const StageConfig = struct {
|
||||
stage_config: ArrayList(Stage),
|
||||
};
|
||||
pub const PlayerIconConfig = struct {
|
||||
player_icon_config: ArrayList(PlayerIcon),
|
||||
};
|
||||
pub const MainMissionConfig = struct {
|
||||
main_mission_config: ArrayList(MainMission),
|
||||
};
|
||||
pub const TutorialGuideConfig = struct {
|
||||
tutorial_guide_config: ArrayList(TutorialGuide),
|
||||
};
|
||||
pub const TutorialConfig = struct {
|
||||
tutorial_config: ArrayList(Tutorial),
|
||||
};
|
||||
pub const ActivityConfig = struct {
|
||||
activity_config: ArrayList(Activity),
|
||||
};
|
||||
pub const ChallengeMazeConfig = struct {
|
||||
challenge_config: ArrayList(ChallengeConfig),
|
||||
};
|
||||
pub const MapEntranceConfig = struct {
|
||||
map_entrance_config: ArrayList(MapEntrance),
|
||||
};
|
||||
pub const MazePlaneConfig = struct {
|
||||
maze_plane_config: ArrayList(MazePlane),
|
||||
};
|
||||
const ErrorSet = error{ CommandError, SystemResources, Unexpected, AccessDenied, WouldBlock, ConnectionResetByPeer, OutOfMemory, DiskQuota, FileTooBig, InputOutput, NoSpaceLeft, DeviceBusy, InvalidArgument, BrokenPipe, OperationAborted, NotOpenForWriting, LockViolation, Overflow, InvalidCharacter, ProcessFdQuotaExceeded, SystemFdQuotaExceeded, SymLinkLoop, NameTooLong, FileNotFound, NotDir, NoDevice, SharingViolation, PathAlreadyExists, PipeBusy, InvalidUtf8, InvalidWtf8, BadPathName, NetworkNotFound, AntivirusInterference, IsDir, FileLocksNotSupported, FileBusy, ConnectionTimedOut, NotOpenForReading, SocketNotConnected, Unseekable, UnexpectedToken, InvalidNumber, InvalidEnumTag, DuplicateField, UnknownField, MissingField, LengthMismatch, SyntaxError, UnexpectedEndOfInput, BufferUnderrun, ValueTooLong, InsufficientTokens, InvalidFormat };
|
||||
|
||||
pub fn loadConfig(
|
||||
comptime ConfigType: type,
|
||||
comptime parseFn: fn (std.json.Value, Allocator) ErrorSet!ConfigType,
|
||||
allocator: Allocator,
|
||||
filename: []const u8,
|
||||
) ErrorSet!ConfigType {
|
||||
const file = try std.fs.cwd().openFile(filename, .{});
|
||||
defer file.close();
|
||||
|
||||
const file_size = try file.getEndPos();
|
||||
const buffer = try file.readToEndAlloc(allocator, file_size);
|
||||
defer allocator.free(buffer);
|
||||
|
||||
var json_tree = try std.json.parseFromSlice(std.json.Value, allocator, buffer, .{});
|
||||
defer json_tree.deinit();
|
||||
|
||||
const root = json_tree.value;
|
||||
return try parseFn(root, allocator);
|
||||
}
|
||||
|
||||
// Specialized loaders
|
||||
pub fn loadGameConfig(allocator: Allocator, filename: []const u8) ErrorSet!GameConfig {
|
||||
return loadConfig(GameConfig, parseConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadStageConfig(allocator: Allocator, filename: []const u8) ErrorSet!StageConfig {
|
||||
return loadConfig(StageConfig, parseStageConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadPlayerIconConfig(allocator: Allocator, filename: []const u8) ErrorSet!PlayerIconConfig {
|
||||
return loadConfig(PlayerIconConfig, parsePlayerIconConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadMainMissionConfig(allocator: Allocator, filename: []const u8) ErrorSet!MainMissionConfig {
|
||||
return loadConfig(MainMissionConfig, parseMainMissionConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadTutorialGuideConfig(allocator: Allocator, filename: []const u8) ErrorSet!TutorialGuideConfig {
|
||||
return loadConfig(TutorialGuideConfig, parseTutorialGuideConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadTutorialConfig(allocator: Allocator, filename: []const u8) ErrorSet!TutorialConfig {
|
||||
return loadConfig(TutorialConfig, parseTutorialConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadActivityConfig(allocator: Allocator, filename: []const u8) ErrorSet!ActivityConfig {
|
||||
return loadConfig(ActivityConfig, parseActivityConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadChallengeConfig(allocator: Allocator, filename: []const u8) ErrorSet!ChallengeMazeConfig {
|
||||
return loadConfig(ChallengeMazeConfig, parseChallengeConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadMapEntranceConfig(allocator: Allocator, filename: []const u8) ErrorSet!MapEntranceConfig {
|
||||
return loadConfig(MapEntranceConfig, parseMapEntranceConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn loadMazePlaneConfig(allocator: Allocator, filename: []const u8) ErrorSet!MazePlaneConfig {
|
||||
return loadConfig(MazePlaneConfig, parseMazePlaneConfig, allocator, filename);
|
||||
}
|
||||
|
||||
pub fn parseConfig(root: std.json.Value, allocator: Allocator) ErrorSet!GameConfig {
|
||||
const battle_config_json = root.object.get("battle_config").?;
|
||||
var battle_config = BattleConfig{
|
||||
.battle_id = @intCast(battle_config_json.object.get("battle_id").?.integer),
|
||||
.stage_id = @intCast(battle_config_json.object.get("stage_id").?.integer),
|
||||
.cycle_count = @intCast(battle_config_json.object.get("cycle_count").?.integer),
|
||||
.monster_wave = ArrayList(ArrayList(u32)).init(allocator),
|
||||
.monster_level = @intCast(battle_config_json.object.get("monster_level").?.integer),
|
||||
.blessings = ArrayList(u32).init(allocator),
|
||||
};
|
||||
|
||||
for (battle_config_json.object.get("monster_wave").?.array.items) |wave| {
|
||||
var wave_list = ArrayList(u32).init(allocator);
|
||||
for (wave.array.items) |monster| {
|
||||
try wave_list.append(@intCast(monster.integer));
|
||||
}
|
||||
try battle_config.monster_wave.append(wave_list);
|
||||
}
|
||||
for (battle_config_json.object.get("blessings").?.array.items) |blessing| {
|
||||
try battle_config.blessings.append(@intCast(blessing.integer));
|
||||
}
|
||||
|
||||
var avatar_config = ArrayList(Avatar).init(allocator);
|
||||
for (root.object.get("avatar_config").?.array.items) |avatar_json| {
|
||||
var avatar = Avatar{
|
||||
.id = @intCast(avatar_json.object.get("id").?.integer),
|
||||
.hp = @intCast(avatar_json.object.get("hp").?.integer),
|
||||
.sp = @intCast(avatar_json.object.get("sp").?.integer),
|
||||
.level = @intCast(avatar_json.object.get("level").?.integer),
|
||||
.promotion = @intCast(avatar_json.object.get("promotion").?.integer),
|
||||
.rank = @intCast(avatar_json.object.get("rank").?.integer),
|
||||
.lightcone = undefined,
|
||||
.relics = ArrayList(Relic).init(allocator),
|
||||
.use_technique = avatar_json.object.get("use_technique").?.bool,
|
||||
};
|
||||
|
||||
const lightcone_json = avatar_json.object.get("lightcone").?;
|
||||
avatar.lightcone = Lightcone{
|
||||
.id = @intCast(lightcone_json.object.get("id").?.integer),
|
||||
.rank = @intCast(lightcone_json.object.get("rank").?.integer),
|
||||
.level = @intCast(lightcone_json.object.get("level").?.integer),
|
||||
.promotion = @intCast(lightcone_json.object.get("promotion").?.integer),
|
||||
};
|
||||
|
||||
for (avatar_json.object.get("relics").?.array.items) |relic_str| {
|
||||
const relic = try parseRelic(relic_str.string, allocator);
|
||||
try avatar.relics.append(relic);
|
||||
}
|
||||
|
||||
try avatar_config.append(avatar);
|
||||
}
|
||||
|
||||
return GameConfig{
|
||||
.battle_config = battle_config,
|
||||
.avatar_config = avatar_config,
|
||||
};
|
||||
}
|
||||
pub fn parseStageConfig(root: std.json.Value, allocator: Allocator) ErrorSet!StageConfig {
|
||||
var stage_config = ArrayList(Stage).init(allocator);
|
||||
for (root.object.get("stage_config").?.array.items) |stage_json| {
|
||||
var stage = Stage{
|
||||
.level = @intCast(stage_json.object.get("Level").?.integer),
|
||||
.stage_id = @intCast(stage_json.object.get("StageID").?.integer),
|
||||
.monster_list = ArrayList(ArrayList(u32)).init(allocator),
|
||||
};
|
||||
|
||||
for (stage_json.object.get("MonsterList").?.array.items) |wave| {
|
||||
var wave_list = ArrayList(u32).init(allocator);
|
||||
for (wave.array.items) |monster| {
|
||||
try wave_list.append(@intCast(monster.integer));
|
||||
}
|
||||
try stage.monster_list.append(wave_list);
|
||||
}
|
||||
|
||||
try stage_config.append(stage);
|
||||
}
|
||||
|
||||
return StageConfig{
|
||||
.stage_config = stage_config,
|
||||
};
|
||||
}
|
||||
fn parsePlayerIconConfig(root: std.json.Value, allocator: Allocator) ErrorSet!PlayerIconConfig {
|
||||
var player_icon_config = ArrayList(PlayerIcon).init(allocator);
|
||||
for (root.object.get("player_icon_config").?.array.items) |icon_json| {
|
||||
const icon = PlayerIcon{
|
||||
.id = @intCast(icon_json.object.get("ID").?.integer),
|
||||
};
|
||||
try player_icon_config.append(icon);
|
||||
}
|
||||
return PlayerIconConfig{
|
||||
.player_icon_config = player_icon_config,
|
||||
};
|
||||
}
|
||||
fn parseMainMissionConfig(root: std.json.Value, allocator: Allocator) ErrorSet!MainMissionConfig {
|
||||
var main_mission_config = ArrayList(MainMission).init(allocator);
|
||||
for (root.object.get("main_mission_config").?.array.items) |main_json| {
|
||||
const main_mission = MainMission{
|
||||
.main_mission_id = @intCast(main_json.object.get("MainMissionID").?.integer),
|
||||
};
|
||||
try main_mission_config.append(main_mission);
|
||||
}
|
||||
return MainMissionConfig{
|
||||
.main_mission_config = main_mission_config,
|
||||
};
|
||||
}
|
||||
fn parseTutorialGuideConfig(root: std.json.Value, allocator: Allocator) ErrorSet!TutorialGuideConfig {
|
||||
var tutorial_guide_config = ArrayList(TutorialGuide).init(allocator);
|
||||
for (root.object.get("tutorial_guide_config").?.array.items) |guide_json| {
|
||||
const tutorial_guide = TutorialGuide{
|
||||
.guide_group_id = @intCast(guide_json.object.get("GroupID").?.integer),
|
||||
};
|
||||
try tutorial_guide_config.append(tutorial_guide);
|
||||
}
|
||||
return TutorialGuideConfig{
|
||||
.tutorial_guide_config = tutorial_guide_config,
|
||||
};
|
||||
}
|
||||
fn parseTutorialConfig(root: std.json.Value, allocator: Allocator) ErrorSet!TutorialConfig {
|
||||
var tutorial_config = ArrayList(Tutorial).init(allocator);
|
||||
for (root.object.get("tutorial_config").?.array.items) |tutorial_json| {
|
||||
const tutorial = Tutorial{
|
||||
.tutorial_id = @intCast(tutorial_json.object.get("TutorialID").?.integer),
|
||||
};
|
||||
try tutorial_config.append(tutorial);
|
||||
}
|
||||
return TutorialConfig{
|
||||
.tutorial_config = tutorial_config,
|
||||
};
|
||||
}
|
||||
fn parseActivityConfig(root: std.json.Value, allocator: Allocator) ErrorSet!ActivityConfig {
|
||||
var activity_config = ArrayList(Activity).init(allocator);
|
||||
for (root.object.get("activity_config").?.array.items) |activity_json| {
|
||||
var activity = Activity{
|
||||
.panel_id = @intCast(activity_json.object.get("ActivityID").?.integer),
|
||||
.activity_module_list = ArrayList(u32).init(allocator),
|
||||
};
|
||||
for (activity_json.object.get("ActivityModuleIDList").?.array.items) |id| {
|
||||
try activity.activity_module_list.append(@intCast(id.integer));
|
||||
}
|
||||
try activity_config.append(activity);
|
||||
}
|
||||
return ActivityConfig{
|
||||
.activity_config = activity_config,
|
||||
};
|
||||
}
|
||||
fn parseChallengeConfig(root: std.json.Value, allocator: Allocator) ErrorSet!ChallengeMazeConfig {
|
||||
var challenge_config = ArrayList(ChallengeConfig).init(allocator);
|
||||
for (root.object.get("challenge_config").?.array.items) |challenge_json| {
|
||||
var challenge = ChallengeConfig{
|
||||
.id = @intCast(challenge_json.object.get("ID").?.integer),
|
||||
.maze_buff_id = @intCast(challenge_json.object.get("MazeBuffID").?.integer),
|
||||
.npc_monster_id_list1 = ArrayList(u32).init(allocator),
|
||||
.npc_monster_id_list2 = ArrayList(u32).init(allocator),
|
||||
.event_id_list1 = ArrayList(u32).init(allocator),
|
||||
.event_id_list2 = ArrayList(u32).init(allocator),
|
||||
.map_entrance_id = @intCast(challenge_json.object.get("MapEntranceID").?.integer),
|
||||
.map_entrance_id2 = @intCast(challenge_json.object.get("MapEntranceID2").?.integer),
|
||||
.maze_group_id1 = @intCast(challenge_json.object.get("MazeGroupID1").?.integer),
|
||||
.maze_group_id2 = if (challenge_json.object.get("MazeGroupID2")) |val| @intCast(val.integer) else null,
|
||||
};
|
||||
for (challenge_json.object.get("NpcMonsterIDList1").?.array.items) |npc1| {
|
||||
try challenge.npc_monster_id_list1.append(@intCast(npc1.integer));
|
||||
}
|
||||
for (challenge_json.object.get("NpcMonsterIDList2").?.array.items) |npc2| {
|
||||
try challenge.npc_monster_id_list2.append(@intCast(npc2.integer));
|
||||
}
|
||||
for (challenge_json.object.get("EventIDList1").?.array.items) |event1| {
|
||||
try challenge.event_id_list1.append(@intCast(event1.integer));
|
||||
}
|
||||
for (challenge_json.object.get("EventIDList2").?.array.items) |event2| {
|
||||
try challenge.event_id_list2.append(@intCast(event2.integer));
|
||||
}
|
||||
try challenge_config.append(challenge);
|
||||
}
|
||||
|
||||
return ChallengeMazeConfig{
|
||||
.challenge_config = challenge_config,
|
||||
};
|
||||
}
|
||||
fn parseMapEntranceConfig(root: std.json.Value, allocator: Allocator) ErrorSet!MapEntranceConfig {
|
||||
var map_entrance_config = ArrayList(MapEntrance).init(allocator);
|
||||
for (root.object.get("map_entrance_config").?.array.items) |mapEntrance| {
|
||||
var entrance = MapEntrance{
|
||||
.id = @intCast(mapEntrance.object.get("ID").?.integer),
|
||||
.floor_id = @intCast(mapEntrance.object.get("FloorID").?.integer),
|
||||
.plane_id = @intCast(mapEntrance.object.get("PlaneID").?.integer),
|
||||
.begin_main_mission_idlist = ArrayList(u32).init(allocator),
|
||||
.finish_main_mission_idlist = ArrayList(u32).init(allocator),
|
||||
.finish_sub_mission_idlist = ArrayList(u32).init(allocator),
|
||||
};
|
||||
for (mapEntrance.object.get("BeginMainMissionList").?.array.items) |id| {
|
||||
try entrance.begin_main_mission_idlist.append(@intCast(id.integer));
|
||||
}
|
||||
for (mapEntrance.object.get("FinishMainMissionList").?.array.items) |id| {
|
||||
try entrance.finish_main_mission_idlist.append(@intCast(id.integer));
|
||||
}
|
||||
for (mapEntrance.object.get("FinishSubMissionList").?.array.items) |id| {
|
||||
try entrance.finish_sub_mission_idlist.append(@intCast(id.integer));
|
||||
}
|
||||
try map_entrance_config.append(entrance);
|
||||
}
|
||||
|
||||
return MapEntranceConfig{
|
||||
.map_entrance_config = map_entrance_config,
|
||||
};
|
||||
}
|
||||
fn parseMazePlaneConfig(root: std.json.Value, allocator: Allocator) ErrorSet!MazePlaneConfig {
|
||||
var maze_plane_config = ArrayList(MazePlane).init(allocator);
|
||||
for (root.object.get("maze_plane_config").?.array.items) |id| {
|
||||
var maze = MazePlane{
|
||||
.start_floor_id = @intCast(id.object.get("StartFloorID").?.integer),
|
||||
.challenge_plane_id = @intCast(id.object.get("PlaneID").?.integer),
|
||||
.world_id = @intCast(id.object.get("WorldID").?.integer),
|
||||
.floor_id_list = ArrayList(u32).init(allocator),
|
||||
};
|
||||
for (id.object.get("FloorIDList").?.array.items) |list| {
|
||||
try maze.floor_id_list.append(@intCast(list.integer));
|
||||
}
|
||||
try maze_plane_config.append(maze);
|
||||
}
|
||||
|
||||
return MazePlaneConfig{
|
||||
.maze_plane_config = maze_plane_config,
|
||||
};
|
||||
}
|
||||
fn parseRelic(relic_str: []const u8, allocator: Allocator) !Relic {
|
||||
var tokens = ArrayList([]const u8).init(allocator);
|
||||
defer tokens.deinit();
|
||||
|
||||
var iterator = std.mem.tokenize(u8, relic_str, ",");
|
||||
|
||||
while (iterator.next()) |token| {
|
||||
try tokens.append(token);
|
||||
}
|
||||
|
||||
const tokens_slice = tokens.items;
|
||||
|
||||
if (tokens_slice.len < 5) {
|
||||
std.debug.print("relic parsing critical error (too few fields): {s}\n", .{relic_str});
|
||||
return error.InsufficientTokens;
|
||||
}
|
||||
|
||||
const stat1 = try parseStatCount(tokens_slice[4]);
|
||||
const stat2 = if (tokens_slice.len > 5) try parseStatCount(tokens_slice[5]) else StatCount{ .stat = 0, .count = 0, .step = 0 };
|
||||
const stat3 = if (tokens_slice.len > 6) try parseStatCount(tokens_slice[6]) else StatCount{ .stat = 0, .count = 0, .step = 0 };
|
||||
const stat4 = if (tokens_slice.len > 7) try parseStatCount(tokens_slice[7]) else StatCount{ .stat = 0, .count = 0, .step = 0 };
|
||||
|
||||
const relic = Relic{
|
||||
.id = try std.fmt.parseInt(u32, tokens_slice[0], 10),
|
||||
.level = try std.fmt.parseInt(u32, tokens_slice[1], 10),
|
||||
.main_affix_id = try std.fmt.parseInt(u32, tokens_slice[2], 10),
|
||||
.sub_count = try std.fmt.parseInt(u32, tokens_slice[3], 10),
|
||||
.stat1 = stat1.stat,
|
||||
.cnt1 = stat1.count,
|
||||
.step1 = stat1.step,
|
||||
.stat2 = stat2.stat,
|
||||
.cnt2 = stat2.count,
|
||||
.step2 = stat2.step,
|
||||
.stat3 = stat3.stat,
|
||||
.cnt3 = stat3.count,
|
||||
.step3 = stat3.step,
|
||||
.stat4 = stat4.stat,
|
||||
.cnt4 = stat4.count,
|
||||
.step4 = stat4.step,
|
||||
};
|
||||
|
||||
return relic;
|
||||
}
|
||||
|
||||
const StatCount = struct {
|
||||
stat: u32,
|
||||
count: u32,
|
||||
step: u32,
|
||||
};
|
||||
|
||||
fn parseStatCount(token: []const u8) !StatCount {
|
||||
if (std.mem.indexOfScalar(u8, token, ':')) |first_colon| {
|
||||
if (std.mem.indexOfScalar(u8, token[first_colon + 1 ..], ':')) |second_colon_offset| {
|
||||
const second_colon = first_colon + 1 + second_colon_offset;
|
||||
const stat = try std.fmt.parseInt(u32, token[0..first_colon], 10);
|
||||
const count = try std.fmt.parseInt(u32, token[first_colon + 1 .. second_colon], 10);
|
||||
const step = try std.fmt.parseInt(u32, token[second_colon + 1 ..], 10);
|
||||
return StatCount{ .stat = stat, .count = count, .step = step };
|
||||
} else {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
} else {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
}
|
37
gameserver/src/services/events.zig
Normal file
37
gameserver/src/services/events.zig
Normal file
|
@ -0,0 +1,37 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("config.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub fn onGetActivity(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetActivityScheduleConfigScRsp.init(allocator);
|
||||
const activity_config = try Config.loadActivityConfig(allocator, "resources/ActivityConfig.json");
|
||||
|
||||
for (activity_config.activity_config.items) |activityConf| {
|
||||
if (activityConf.panel_id != 30002) {
|
||||
for (activityConf.activity_module_list.items) |id| {
|
||||
var activ_list = protocol.ActivityScheduleData.init(allocator);
|
||||
activ_list.begin_time = 1664308800;
|
||||
activ_list.end_time = 4294967295;
|
||||
activ_list.activity_id = id;
|
||||
activ_list.panel_id = activityConf.panel_id;
|
||||
try rsp.schedule_data.append(activ_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdGetActivityScheduleConfigScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onUpdateServerPrefsData(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.UpdateServerPrefsDataScRsp.init(allocator);
|
||||
const req = try packet.getProto(protocol.UpdateServerPrefsDataCsReq, allocator);
|
||||
rsp.server_prefs_id = req.server_prefs.?.server_prefs_id;
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdUpdateServerPrefsDataScRsp, rsp);
|
||||
}
|
222
gameserver/src/services/gacha.zig
Normal file
222
gameserver/src/services/gacha.zig
Normal file
|
@ -0,0 +1,222 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const GachaData = @import("../commands/value.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
// function to check the list if true
|
||||
fn isInList(id: u32, list: []const u32) bool {
|
||||
for (list) |item| {
|
||||
if (item == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn onGetGachaInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var info = ArrayList(protocol.GachaCeilingAvatar).init(allocator);
|
||||
for (GachaData.StandardBanner) |id| {
|
||||
try info.appendSlice(&[_]protocol.GachaCeilingAvatar{
|
||||
.{ .RepeatedCnt = 300, .avatar_id = id },
|
||||
});
|
||||
}
|
||||
var gacha_info = protocol.GachaInfo.init(allocator);
|
||||
gacha_info.begin_time = 0;
|
||||
gacha_info.end_time = 2524608000;
|
||||
gacha_info.gacha_ceiling = .{
|
||||
.avatar_list = info,
|
||||
.is_claimed = false,
|
||||
.ceiling_num = 200,
|
||||
};
|
||||
gacha_info.KMNJNMJFGBG = 1;
|
||||
gacha_info.GDIFAAHIFBH = 3;
|
||||
gacha_info.gacha_id = 1001; // standard banner
|
||||
|
||||
var rsp = protocol.GetGachaInfoScRsp.init(allocator);
|
||||
|
||||
rsp.retcode = 0;
|
||||
rsp.DJNDMNPEBKA = 20;
|
||||
rsp.NOPBEBKHIKA = 20;
|
||||
rsp.NBELNOIPOEK = 900;
|
||||
rsp.gacha_random = 0;
|
||||
try rsp.gacha_info_list.append(gacha_info);
|
||||
|
||||
try session.send(CmdID.CmdGetGachaInfoScRsp, rsp);
|
||||
}
|
||||
pub fn onBuyGoods(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.BuyGoodsCsReq, allocator);
|
||||
|
||||
var rsp = protocol.BuyGoodsScRsp.init(allocator);
|
||||
var item = ArrayList(protocol.Item).init(allocator);
|
||||
|
||||
try item.appendSlice(&[_]protocol.Item{.{
|
||||
.ItemId = 101,
|
||||
.Num = 100,
|
||||
}});
|
||||
|
||||
rsp.retcode = 0;
|
||||
rsp.GoodsId = req.goods_id;
|
||||
rsp.GoodsBuyTimes = req.goods_num;
|
||||
rsp.ShopId = 0;
|
||||
rsp.ReturnItemList = .{ .ItemList_ = item };
|
||||
|
||||
try session.send(CmdID.CmdBuyGoodsScRsp, rsp);
|
||||
}
|
||||
pub fn onGetShopList(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetShopListScRsp.init(allocator);
|
||||
var shop = ArrayList(protocol.Shop).init(allocator);
|
||||
var goods = ArrayList(protocol.Goods).init(allocator);
|
||||
|
||||
try shop.appendSlice(&[_]protocol.Shop{.{
|
||||
.ShopId = 1000,
|
||||
.GoodsList = goods,
|
||||
}});
|
||||
try goods.appendSlice(&[_]protocol.Goods{.{
|
||||
.GoodsId = 101001,
|
||||
.ItemId = 101,
|
||||
.BuyTimes = 0,
|
||||
}});
|
||||
|
||||
rsp.retcode = 0;
|
||||
rsp.ShopType = 101;
|
||||
rsp.ShopList = shop;
|
||||
|
||||
try session.send(CmdID.CmdGetShopListScRsp, rsp);
|
||||
}
|
||||
pub fn onExchangeHcoin(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.ExchangeHcoinCsReq, allocator);
|
||||
|
||||
var rsp = protocol.ExchangeHcoinScRsp.init(allocator);
|
||||
rsp.Num = req.Num;
|
||||
rsp.retcode = 0;
|
||||
|
||||
try session.send(CmdID.CmdExchangeHcoinScRsp, rsp);
|
||||
}
|
||||
|
||||
var five_star_pity: u32 = 0;
|
||||
var four_star_pity: u32 = 0;
|
||||
var guaranteed_five_star_rate_up: bool = false;
|
||||
var guaranteed_four_star_rate_up: bool = false;
|
||||
var avatar_list_cached: ?std.ArrayList(u32) = null;
|
||||
var lightcone_list_3_cached: ?std.ArrayList(u32) = null;
|
||||
var lightcone_list_4_cached: ?std.ArrayList(u32) = null;
|
||||
fn pow(base: f64, exp: f64) f64 {
|
||||
return @exp(exp * @log(base));
|
||||
}
|
||||
fn getFiveStarRate(gacha_count: u32) f64 {
|
||||
if (gacha_count < 21) {
|
||||
return 0.02;
|
||||
}
|
||||
if (gacha_count < 72) {
|
||||
return 0.008;
|
||||
}
|
||||
const excess_pulls = @as(f64, @floatFromInt(gacha_count - 71));
|
||||
return 0.008 + (1.0 - 0.008) * pow(excess_pulls / 18.0, 2.8);
|
||||
}
|
||||
fn getFourStarRate(gacha_count: u32) f64 {
|
||||
if (gacha_count < 6) {
|
||||
return 0.055;
|
||||
}
|
||||
const excess_pulls = @as(f64, @floatFromInt(gacha_count - 5));
|
||||
return 0.055 + (1.0 - 0.055) * pow(excess_pulls / 3.5, 2.2);
|
||||
}
|
||||
fn pickRandomId(rnd: *std.rand.Random, banner: []const u32) u32 {
|
||||
return banner[rnd.int(usize) % banner.len];
|
||||
}
|
||||
|
||||
pub fn onDoGacha(session: *Session, packet: *const Packet, allocator: std.mem.Allocator) !void {
|
||||
const req = try packet.getProto(protocol.DoGachaCsReq, allocator);
|
||||
var rsp = protocol.DoGachaScRsp.init(allocator);
|
||||
var seed: u64 = undefined;
|
||||
try std.posix.getrandom(std.mem.asBytes(&seed));
|
||||
var prng = std.rand.DefaultPrng.init(seed);
|
||||
var rnd = prng.random();
|
||||
var selected_ids = std.ArrayList(u32).init(allocator);
|
||||
defer selected_ids.deinit();
|
||||
var got_four_star = false;
|
||||
for (0..req.gacha_num) |_| {
|
||||
const five_star_rate = getFiveStarRate(five_star_pity);
|
||||
const four_star_rate = getFourStarRate(four_star_pity);
|
||||
const random_value = rnd.float(f64);
|
||||
var selected_banner: []const u32 = &Data.LightconeList_3;
|
||||
var is_five_star = false;
|
||||
var is_four_star = false;
|
||||
if (random_value < five_star_rate or five_star_pity == 89) {
|
||||
is_five_star = true;
|
||||
five_star_pity = 0;
|
||||
if (guaranteed_five_star_rate_up) {
|
||||
selected_banner = &GachaData.RateUp;
|
||||
guaranteed_five_star_rate_up = false;
|
||||
} else {
|
||||
if (rnd.boolean()) {
|
||||
selected_banner = &GachaData.RateUp;
|
||||
} else {
|
||||
selected_banner = &GachaData.StandardBanner;
|
||||
guaranteed_five_star_rate_up = true;
|
||||
}
|
||||
}
|
||||
} else if (four_star_pity == 9 or random_value < (five_star_rate + four_star_rate)) {
|
||||
is_four_star = true;
|
||||
four_star_pity = 0;
|
||||
got_four_star = true;
|
||||
|
||||
if (guaranteed_four_star_rate_up or rnd.float(f64) < 0.70) {
|
||||
selected_banner = &GachaData.RateUpFourStars;
|
||||
guaranteed_four_star_rate_up = false;
|
||||
} else {
|
||||
if (rnd.boolean()) {
|
||||
selected_banner = &Data.AvatarList;
|
||||
} else {
|
||||
selected_banner = &Data.LightconeList_4;
|
||||
}
|
||||
guaranteed_four_star_rate_up = true;
|
||||
}
|
||||
} else {
|
||||
four_star_pity += 1;
|
||||
}
|
||||
five_star_pity += 1;
|
||||
try selected_ids.append(pickRandomId(&rnd, selected_banner));
|
||||
}
|
||||
if (req.gacha_num > 1 and !got_four_star) {
|
||||
selected_ids.items[rnd.int(usize) % selected_ids.items.len] = pickRandomId(&rnd, &GachaData.RateUpFourStars);
|
||||
}
|
||||
for (selected_ids.items) |id| {
|
||||
var gacha_item = protocol.GachaItem.init(allocator);
|
||||
gacha_item.gacha_item = .{ .ItemId = id };
|
||||
gacha_item.is_new = false;
|
||||
var back_item = std.ArrayList(protocol.Item).init(allocator);
|
||||
var transfer_item = std.ArrayList(protocol.Item).init(allocator);
|
||||
if (id < 10000) {
|
||||
if (isInList(id, &GachaData.RateUp) or isInList(id, &GachaData.StandardBanner)) {
|
||||
try transfer_item.appendSlice(&[_]protocol.Item{
|
||||
.{ .ItemId = id + 10000, .Num = 1 },
|
||||
.{ .ItemId = 252, .Num = 20 },
|
||||
});
|
||||
} else {
|
||||
try transfer_item.append(.{ .ItemId = 252, .Num = 20 });
|
||||
}
|
||||
}
|
||||
try back_item.append(.{ .ItemId = 252, .Num = 20 });
|
||||
gacha_item.transfer_item_list = .{ .ItemList_ = transfer_item };
|
||||
gacha_item.token_item = .{ .ItemList_ = back_item };
|
||||
try rsp.gacha_item_list.append(gacha_item);
|
||||
}
|
||||
rsp.gacha_num = req.gacha_num;
|
||||
rsp.gacha_id = req.gacha_id;
|
||||
rsp.ceiling_num = 200;
|
||||
rsp.KMNJNMJFGBG = 1;
|
||||
rsp.NOPBEBKHIKA = 20;
|
||||
rsp.GDIFAAHIFBH = 3;
|
||||
rsp.retcode = 0;
|
||||
|
||||
std.debug.print("FIVE STAR PITY: {}, (RATE: {d:.4}%)\n", .{ five_star_pity, getFiveStarRate(five_star_pity) * 100.0 });
|
||||
std.debug.print("FOUR STAR PITY: {}, (RATE: {d:.4}%)\n", .{ four_star_pity, getFourStarRate(four_star_pity) * 100.0 });
|
||||
|
||||
try session.send(protocol.CmdID.CmdDoGachaScRsp, rsp);
|
||||
}
|
92
gameserver/src/services/item.zig
Normal file
92
gameserver/src/services/item.zig
Normal file
|
@ -0,0 +1,92 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const LineupManager = @import("../manager/lineup_mgr.zig").LineupManager;
|
||||
const Sync = @import("../commands/sync.zig");
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub fn onGetBag(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
const config = try Config.loadGameConfig(allocator, "config.json");
|
||||
var generator = UidGenerator().init();
|
||||
// fake item inventory
|
||||
// TODO: make real one
|
||||
var rsp = protocol.GetBagScRsp.init(allocator);
|
||||
rsp.equipment_list = ArrayList(protocol.Equipment).init(allocator);
|
||||
rsp.relic_list = ArrayList(protocol.Relic).init(allocator);
|
||||
|
||||
for (Data.ItemList) |tid| {
|
||||
try rsp.material_list.append(.{ .tid = tid, .Num = 100 });
|
||||
}
|
||||
|
||||
for (config.avatar_config.items) |avatarConf| {
|
||||
// lc
|
||||
const lc = protocol.Equipment{
|
||||
.unique_id = generator.nextId(),
|
||||
.tid = avatarConf.lightcone.id, // id
|
||||
.is_protected = true, // lock
|
||||
.level = avatarConf.lightcone.level,
|
||||
.rank = avatarConf.lightcone.rank,
|
||||
.promotion = avatarConf.lightcone.promotion,
|
||||
.equip_avatar_id = avatarConf.id, // base avatar id
|
||||
};
|
||||
try rsp.equipment_list.append(lc);
|
||||
|
||||
// relics
|
||||
for (avatarConf.relics.items) |input| {
|
||||
var r = protocol.Relic{
|
||||
.tid = input.id, // id
|
||||
.main_affix_id = input.main_affix_id,
|
||||
.unique_id = generator.nextId(),
|
||||
.exp = 0,
|
||||
.equip_avatar_id = avatarConf.id, // base avatar id
|
||||
.is_protected = true, // lock
|
||||
.level = input.level,
|
||||
.sub_affix_list = ArrayList(protocol.RelicAffix).init(allocator),
|
||||
.reforge_sub_affix_list = ArrayList(protocol.RelicAffix).init(allocator),
|
||||
};
|
||||
try r.sub_affix_list.append(protocol.RelicAffix{ .affix_id = input.stat1, .cnt = input.cnt1, .step = input.step1 });
|
||||
try r.sub_affix_list.append(protocol.RelicAffix{ .affix_id = input.stat2, .cnt = input.cnt2, .step = input.step2 });
|
||||
try r.sub_affix_list.append(protocol.RelicAffix{ .affix_id = input.stat3, .cnt = input.cnt3, .step = input.step3 });
|
||||
try r.sub_affix_list.append(protocol.RelicAffix{ .affix_id = input.stat4, .cnt = input.cnt4, .step = input.step4 });
|
||||
try rsp.relic_list.append(r);
|
||||
}
|
||||
}
|
||||
try session.send(CmdID.CmdGetBagScRsp, rsp);
|
||||
}
|
||||
pub fn onUseItem(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.UseItemCsReq, allocator);
|
||||
var rsp = protocol.UseItemScRsp.init(allocator);
|
||||
rsp.use_item_id = req.use_item_id;
|
||||
rsp.use_item_count = req.use_item_count;
|
||||
rsp.retcode = 0;
|
||||
var sync = protocol.SyncLineupNotify.init(allocator);
|
||||
var lineup_mgr = LineupManager.init(allocator);
|
||||
const lineup = try lineup_mgr.createLineup();
|
||||
sync.Lineup = lineup;
|
||||
try session.send(CmdID.CmdSyncLineupNotify, sync);
|
||||
try session.send(CmdID.CmdUseItemScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn UidGenerator() type {
|
||||
return struct {
|
||||
current_id: u32,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init() Self {
|
||||
return Self{ .current_id = 0 };
|
||||
}
|
||||
pub fn curId(self: *const Self) u32 {
|
||||
return self.current_id;
|
||||
}
|
||||
pub fn nextId(self: *Self) u32 {
|
||||
self.current_id +%= 1; // Using wrapping addition
|
||||
return self.current_id;
|
||||
}
|
||||
};
|
||||
}
|
71
gameserver/src/services/lineup.zig
Normal file
71
gameserver/src/services/lineup.zig
Normal file
|
@ -0,0 +1,71 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("config.zig");
|
||||
const LineupManager = @import("../manager/lineup_mgr.zig");
|
||||
const BattleManager = @import("../manager/battle_mgr.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub fn onGetCurLineupData(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var lineup_mgr = LineupManager.LineupManager.init(allocator);
|
||||
const lineup = try lineup_mgr.createLineup();
|
||||
try session.send(CmdID.CmdGetCurLineupDataScRsp, protocol.GetCurLineupDataScRsp{
|
||||
.retcode = 0,
|
||||
.lineup = lineup,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn onChangeLineupLeader(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.ChangeLineupLeaderCsReq, allocator);
|
||||
try session.send(CmdID.CmdChangeLineupLeaderScRsp, protocol.ChangeLineupLeaderScRsp{
|
||||
.slot = req.slot,
|
||||
.retcode = 0,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn onReplaceLineup(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.ReplaceLineupCsReq, allocator);
|
||||
var lineup = protocol.LineupInfo.init(allocator);
|
||||
lineup.mp = 5;
|
||||
lineup.max_mp = 5;
|
||||
lineup.name = .{ .Const = "JingliuSR" };
|
||||
for (req.lineup_slot_list.items) |ok| {
|
||||
const avatar = protocol.LineupAvatar{
|
||||
.id = ok.id,
|
||||
.slot = ok.slot,
|
||||
.satiety = 0,
|
||||
.hp = 10000,
|
||||
.avatar_type = protocol.AvatarType.AVATAR_FORMAL_TYPE,
|
||||
.sp_bar = .{ .sp_cur = 10000, .sp_max = 10000 },
|
||||
};
|
||||
try lineup.avatar_list.append(avatar);
|
||||
}
|
||||
|
||||
var id_list = try allocator.alloc(u32, req.lineup_slot_list.items.len);
|
||||
defer allocator.free(id_list);
|
||||
for (req.lineup_slot_list.items, 0..) |slot, idx| {
|
||||
if (idx >= 4) {
|
||||
break;
|
||||
}
|
||||
id_list[idx] = slot.id;
|
||||
}
|
||||
try LineupManager.getSelectedAvatarID(allocator, id_list);
|
||||
|
||||
var rsp = protocol.SyncLineupNotify.init(allocator);
|
||||
rsp.Lineup = lineup;
|
||||
try session.send(CmdID.CmdSyncLineupNotify, rsp);
|
||||
try session.send(CmdID.CmdReplaceLineupScRsp, protocol.ReplaceLineupScRsp{
|
||||
.retcode = 0,
|
||||
});
|
||||
}
|
||||
pub fn onSetLineupName(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SetLineupNameCsReq, allocator);
|
||||
try session.send(CmdID.CmdSetLineupNameScRsp, protocol.SetLineupNameScRsp{
|
||||
.index = req.index,
|
||||
.name = req.name,
|
||||
.retcode = 0,
|
||||
});
|
||||
}
|
83
gameserver/src/services/login.zig
Normal file
83
gameserver/src/services/login.zig
Normal file
|
@ -0,0 +1,83 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub fn onPlayerGetToken(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.PlayerGetTokenScRsp.init(allocator);
|
||||
|
||||
rsp.retcode = 0;
|
||||
rsp.uid = 1;
|
||||
|
||||
try session.send(CmdID.CmdPlayerGetTokenScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onPlayerLogin(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.PlayerLoginCsReq, allocator);
|
||||
|
||||
var basic_info = protocol.PlayerBasicInfo.init(allocator);
|
||||
basic_info.stamina = 300;
|
||||
basic_info.level = 70;
|
||||
basic_info.nickname = .{ .Const = "ReversedRooms" };
|
||||
basic_info.world_level = 6;
|
||||
basic_info.mcoin = 99999990;
|
||||
basic_info.hcoin = 99999990; //Jade
|
||||
basic_info.scoin = 99999990; //Money
|
||||
|
||||
var rsp = protocol.PlayerLoginScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.login_random = req.login_random;
|
||||
rsp.stamina = 300;
|
||||
rsp.basic_info = basic_info;
|
||||
|
||||
try session.send(CmdID.CmdPlayerLoginScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onPlayerLoginFinish(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
const content = [_]u32{
|
||||
200001, 200002, 200003, 200004, 200005, 200006, 200007, 200008,
|
||||
150017, 150015, 150021, 150018, 130011, 130012, 130013, 150025,
|
||||
140006, 150026, 130014, 150034, 150029, 150035, 150041, 150039,
|
||||
150045,
|
||||
};
|
||||
|
||||
var package_data = protocol.ContentPackageData.init(allocator);
|
||||
package_data.cur_content_id = 0;
|
||||
for (content) |id| {
|
||||
try package_data.content_package_list.append(protocol.ContentPackageInfo{
|
||||
.content_id = id,
|
||||
.status = protocol.ContentPackageStatus.ContentPackageStatus_Finished,
|
||||
});
|
||||
}
|
||||
|
||||
var noti = protocol.UnlockAvatarSkinScNotify.init(allocator);
|
||||
noti.skin_id = 1100101;
|
||||
try session.send(CmdID.CmdUnlockAvatarSkinScNotify, noti);
|
||||
var phone = protocol.UnlockPhoneCaseScNotify.init(allocator);
|
||||
phone.phone_case_id = 254000;
|
||||
try session.send(CmdID.CmdUnlockPhoneCaseScNotify, phone);
|
||||
try session.send(CmdID.CmdContentPackageSyncDataScNotify, protocol.ContentPackageSyncDataScNotify{
|
||||
.data = package_data,
|
||||
});
|
||||
try session.send(CmdID.CmdPlayerLoginFinishScRsp, protocol.PlayerLoginFinishScRsp{
|
||||
.retcode = 0,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn onContentPackageGetData(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.ContentPackageGetDataScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdContentPackageGetDataScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onSetClientPaused(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SetClientPausedCsReq, allocator);
|
||||
try session.send(CmdID.CmdSetClientPausedScRsp, protocol.SetClientPausedScRsp{
|
||||
.retcode = 0,
|
||||
.paused = req.paused,
|
||||
});
|
||||
}
|
39
gameserver/src/services/mail.zig
Normal file
39
gameserver/src/services/mail.zig
Normal file
|
@ -0,0 +1,39 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
const B64Decoder = std.base64.standard.Decoder;
|
||||
|
||||
pub fn onGetMail(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetMailScRsp.init(allocator);
|
||||
var item_attachment = ArrayList(protocol.Item).init(allocator);
|
||||
try item_attachment.appendSlice(&[_]protocol.Item{
|
||||
.{ .ItemId = 1407, .Num = 1 },
|
||||
});
|
||||
var mail = protocol.ClientMail.init(allocator);
|
||||
mail.Sender = .{ .Const = "Castorice" };
|
||||
mail.Title = .{ .Const = "Readme" };
|
||||
mail.IsRead = false;
|
||||
mail.id = 1;
|
||||
mail.Content = .{ .Const = "JingliuSR is a free and open-source sofware\nJoin our discord: https://discord.gg/reversedrooms\nUse https://yunlisr-relic-builder.vercel.app to setup relic :Đ\nAND DO NOT CLAIM THIS MAIL :>" };
|
||||
mail.Time = 1723334400;
|
||||
mail.ExpireTime = 17186330890;
|
||||
mail.MailType = protocol.MailType.MAIL_TYPE_STAR;
|
||||
mail.Attachment = .{ .ItemList_ = item_attachment };
|
||||
|
||||
var mail_list = ArrayList(protocol.ClientMail).init(allocator);
|
||||
try mail_list.append(mail);
|
||||
|
||||
rsp.TotalNum = 1;
|
||||
rsp.IsEnd = true;
|
||||
rsp.Start = 0;
|
||||
rsp.retcode = 0;
|
||||
rsp.MailList = mail_list;
|
||||
|
||||
try session.send(CmdID.CmdGetMailScRsp, rsp);
|
||||
}
|
31
gameserver/src/services/misc.zig
Normal file
31
gameserver/src/services/misc.zig
Normal file
|
@ -0,0 +1,31 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub fn onPlayerHeartBeat(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.PlayerHeartBeatCsReq, allocator);
|
||||
defer req.deinit();
|
||||
|
||||
const encoded = "ICAgICAgICBsb2NhbCBmdW5jdGlvbiBzZXRUZXh0Q29tcG9uZW50KHBhdGgsIG5ld1RleHQpDQogICAgICAgICAgICBsb2NhbCBvYmogPSBDUy5Vbml0eUVuZ2luZS5HYW1lT2JqZWN0LkZpbmQocGF0aCkNCiAgICAgICAgICAgIGlmIG9iaiB0aGVuDQogICAgICAgICAgICAgICAgbG9jYWwgdGV4dENvbXBvbmVudCA9IG9iajpHZXRDb21wb25lbnRJbkNoaWxkcmVuKHR5cGVvZihDUy5SUEcuQ2xpZW50LkxvY2FsaXplZFRleHQpKQ0KICAgICAgICAgICAgICAgIGlmIHRleHRDb21wb25lbnQgdGhlbg0KICAgICAgICAgICAgICAgICAgICB0ZXh0Q29tcG9uZW50LnRleHQgPSBuZXdUZXh0DQogICAgICAgICAgICAgICAgZW5kDQogICAgICAgICAgICBlbmQNCiAgICAgICAgZW5kDQogICAgICAgIA0KICAgICAgICBzZXRUZXh0Q29tcG9uZW50KCJVSVJvb3QvQWJvdmVEaWFsb2cvQmV0YUhpbnREaWFsb2coQ2xvbmUpIiwgIjxjb2xvcj0jMDNmNGZjPkppbmdsaXVTUiBpcyBhIGZyZWUgYW5kIG9wZW4gc291cmNlIHNvZnR3YXJlLjwvY29sb3I+IikNCiAgICAgICAgc2V0VGV4dENvbXBvbmVudCgiVmVyc2lvblRleHQiLCAiPGNvbG9yPSMwM2Y0ZmM+VmlzaXQgZGlzY29yZC5nZy9yZXZlcnNlZHJvb21zIGZvciBtb3JlIGluZm8hPC9jb2xvcj4iKQ0K";
|
||||
|
||||
const dest_buf = try allocator.alloc(u8, try std.base64.standard.Decoder.calcSizeForSlice(encoded));
|
||||
try std.base64.standard.Decoder.decode(dest_buf, encoded);
|
||||
|
||||
const managed_str = protocol.ManagedString.move(dest_buf, allocator);
|
||||
const download_data = protocol.ClientDownloadData{
|
||||
.version = 51,
|
||||
.time = @intCast(std.time.milliTimestamp()),
|
||||
.data = managed_str,
|
||||
};
|
||||
|
||||
try session.send(CmdID.CmdPlayerHeartBeatScRsp, protocol.PlayerHeartBeatScRsp{
|
||||
.retcode = 0,
|
||||
.client_time_ms = req.client_time_ms,
|
||||
.server_time_ms = @intCast(std.time.milliTimestamp()),
|
||||
.download_data = download_data,
|
||||
});
|
||||
}
|
64
gameserver/src/services/mission.zig
Normal file
64
gameserver/src/services/mission.zig
Normal file
|
@ -0,0 +1,64 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const Config = @import("config.zig");
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub fn onGetMissionStatus(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.GetMissionStatusCsReq, allocator);
|
||||
var rsp = protocol.GetMissionStatusScRsp.init(allocator);
|
||||
const main_mission_config = try Config.loadMainMissionConfig(allocator, "resources/MainMission.json");
|
||||
rsp.retcode = 0;
|
||||
for (req.sub_mission_id_list.items) |id| {
|
||||
try rsp.SubMissionStatusList.append(protocol.Mission{ .id = id, .status = protocol.MissionStatus.MISSION_FINISH, .progress = 1 });
|
||||
}
|
||||
for (main_mission_config.main_mission_config.items) |main_missionConf| {
|
||||
try rsp.FinishedMainMissionIdList.append(main_missionConf.main_mission_id);
|
||||
try rsp.CurversionFinishedMainMissionIdList.append(main_missionConf.main_mission_id);
|
||||
}
|
||||
try session.send(CmdID.CmdGetMissionStatusScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onGetTutorialGuideStatus(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetTutorialGuideScRsp.init(allocator);
|
||||
const tutorial_guide_config = try Config.loadTutorialGuideConfig(allocator, "resources/TutorialGuideGroup.json");
|
||||
|
||||
rsp.retcode = 0;
|
||||
for (tutorial_guide_config.tutorial_guide_config.items) |guideConf| {
|
||||
try rsp.TutorialGuideList.append(protocol.TutorialGuide{ .id = guideConf.guide_group_id, .status = protocol.TutorialStatus.TUTORIAL_FINISH });
|
||||
}
|
||||
|
||||
try session.send(CmdID.CmdGetTutorialGuideScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onGetTutorialStatus(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetTutorialScRsp.init(allocator);
|
||||
const tutorial_guide_config = try Config.loadTutorialConfig(allocator, "resources/TutorialData.json");
|
||||
rsp.retcode = 0;
|
||||
for (tutorial_guide_config.tutorial_config.items) |tutorialConf| {
|
||||
try rsp.TutorialList.append(protocol.Tutorial{ .id = tutorialConf.tutorial_id, .status = protocol.TutorialStatus.TUTORIAL_FINISH });
|
||||
}
|
||||
try session.send(CmdID.CmdGetTutorialScRsp, rsp);
|
||||
}
|
||||
|
||||
// added this to auto detect new tutorial guide id
|
||||
pub fn onUnlockTutorialGuide(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.UnlockTutorialGuideCsReq, allocator);
|
||||
var rsp = protocol.UnlockTutorialGuideScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
std.debug.print("UNLOCK TUTORIAL GUIDE ID: {}\n", .{req.group_id});
|
||||
try session.send(CmdID.CmdUnlockTutorialGuideScRsp, rsp);
|
||||
}
|
||||
// added this to auto detect new tutorial id
|
||||
pub fn onUnlockTutorial(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.UnlockTutorialCsReq, allocator);
|
||||
var rsp = protocol.UnlockTutorialScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
std.debug.print("UNLOCK TUTORIAL ID: {}\n", .{req.tutorial_id});
|
||||
try session.send(CmdID.CmdUnlockTutorialScRsp, rsp);
|
||||
}
|
17
gameserver/src/services/multipath.zig
Normal file
17
gameserver/src/services/multipath.zig
Normal file
|
@ -0,0 +1,17 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const MultiPathManager = @import("../manager/multipath_mgr.zig").MultiPathManager;
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
pub fn onGetMultiPathAvatarInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var multipath = MultiPathManager.init(allocator);
|
||||
const rsp = try multipath.createMultiPath(1100101);
|
||||
try session.send(CmdID.CmdGetMultiPathAvatarInfoScRsp, rsp);
|
||||
}
|
36
gameserver/src/services/pet.zig
Normal file
36
gameserver/src/services/pet.zig
Normal file
|
@ -0,0 +1,36 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
const OwnedPet = [_]u32{ 251001, 251002 };
|
||||
|
||||
pub fn onGetPetData(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetPetDataScRsp.init(allocator);
|
||||
|
||||
rsp.retcode = 0;
|
||||
rsp.cur_pet_id = 1002;
|
||||
try rsp.unlocked_pet_id.appendSlice(&OwnedPet);
|
||||
|
||||
try session.send(CmdID.CmdGetPetDataScRsp, rsp);
|
||||
}
|
||||
pub fn onRecallPet(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.RecallPetScRsp.init(allocator);
|
||||
|
||||
rsp.retcode = 0;
|
||||
rsp.cur_pet_id = 1002;
|
||||
try session.send(CmdID.CmdRecallPetScRsp, rsp);
|
||||
}
|
||||
pub fn onSummonPet(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.CurPetChangedScNotify.init(allocator);
|
||||
|
||||
rsp.cur_pet_id = 1002;
|
||||
try session.send(CmdID.CmdCurPetChangedScNotify, rsp);
|
||||
try session.send(CmdID.CmdSummonPetScRsp, protocol.SummonPetScRsp{
|
||||
.retcode = 0,
|
||||
.cur_pet_id = rsp.cur_pet_id,
|
||||
});
|
||||
}
|
119
gameserver/src/services/profile.zig
Normal file
119
gameserver/src/services/profile.zig
Normal file
|
@ -0,0 +1,119 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const Config = @import("config.zig");
|
||||
|
||||
const UidGenerator = @import("item.zig").UidGenerator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
// can change these id here for initial display
|
||||
const SupportAvatar = [_]u32{
|
||||
1407, 1403, 1402,
|
||||
};
|
||||
const ListAvatar = [_]u32{
|
||||
1401, 1001, 1225, 1317, 1222,
|
||||
};
|
||||
|
||||
pub fn onGetPhoneData(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetPhoneDataScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.cur_chat_bubble = 0;
|
||||
rsp.cur_phone_theme = 0;
|
||||
rsp.cur_phone_case = 254000;
|
||||
try rsp.owned_chat_bubbles.appendSlice(&Data.OwnedChatBubbles);
|
||||
try rsp.owned_phone_themes.appendSlice(&Data.OwnedPhoneThemes);
|
||||
try rsp.owned_phone_cases.appendSlice(&Data.OwnedPhoneCases);
|
||||
try session.send(CmdID.CmdGetPhoneDataScRsp, rsp);
|
||||
}
|
||||
pub fn onSelectPhoneTheme(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SelectPhoneThemeCsReq, allocator);
|
||||
var rsp = protocol.SelectPhoneThemeScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.cur_phone_theme = req.theme_id;
|
||||
try session.send(CmdID.CmdSelectPhoneThemeScRsp, rsp);
|
||||
}
|
||||
pub fn onSelectChatBubble(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SelectChatBubbleCsReq, allocator);
|
||||
var rsp = protocol.SelectChatBubbleScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.cur_chat_bubble = req.bubble_id;
|
||||
try session.send(CmdID.CmdSelectChatBubbleScRsp, rsp);
|
||||
}
|
||||
pub fn onGetPlayerBoardData(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetPlayerBoardDataScRsp.init(allocator);
|
||||
var generator = UidGenerator().init();
|
||||
var display_list = protocol.DisplayAvatarVec.init(allocator);
|
||||
const player_icon_config = try Config.loadPlayerIconConfig(allocator, "resources/AvatarPlayerIcon.json");
|
||||
display_list.is_display = true;
|
||||
rsp.retcode = 0;
|
||||
rsp.OLDMJONBJOM = 253000;
|
||||
rsp.signature = .{ .Const = "" };
|
||||
try rsp.assist_avatar_id_list.appendSlice(&SupportAvatar);
|
||||
for (ListAvatar) |id| {
|
||||
var A_list = protocol.DisplayAvatarData.init(allocator);
|
||||
A_list.avatar_id = id;
|
||||
A_list.pos = generator.nextId();
|
||||
try display_list.display_avatar_list.append(A_list);
|
||||
}
|
||||
rsp.display_avatar_vec = display_list;
|
||||
for (player_icon_config.player_icon_config.items) |head_id| {
|
||||
const head_icon = protocol.HeadIconData{
|
||||
.id = head_id.id,
|
||||
};
|
||||
try rsp.unlocked_head_icon_list.append(head_icon);
|
||||
}
|
||||
for (Data.OwnedPersonalCardSkin) |card_skin_id| {
|
||||
try rsp.KKNJHENMGPK.append(card_skin_id);
|
||||
}
|
||||
try session.send(CmdID.CmdGetPlayerBoardDataScRsp, rsp);
|
||||
}
|
||||
pub fn onSetAssistAvatar(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SetAssistAvatarCsReq, allocator);
|
||||
var rsp = protocol.SetAssistAvatarScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.avatar_id = req.avatar_id;
|
||||
rsp.avatar_id_list = req.avatar_id_list;
|
||||
try session.send(CmdID.CmdSetAssistAvatarScRsp, rsp);
|
||||
}
|
||||
pub fn onSetDisplayAvatar(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SetDisplayAvatarCsReq, allocator);
|
||||
var rsp = protocol.SetDisplayAvatarScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.display_avatar_list = req.display_avatar_list;
|
||||
try session.send(CmdID.CmdSetDisplayAvatarScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onSetSignature(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SetSignatureCsReq, allocator);
|
||||
var rsp = protocol.SetSignatureScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.signature = req.signature;
|
||||
try session.send(CmdID.CmdSetSignatureScRsp, rsp);
|
||||
}
|
||||
pub fn onSetGameplayBirthday(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SetGameplayBirthdayCsReq, allocator);
|
||||
var rsp = protocol.SetGameplayBirthdayScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.birthday = req.birthday;
|
||||
try session.send(CmdID.CmdSetGameplayBirthdayScRsp, rsp);
|
||||
}
|
||||
pub fn onSetHeadIcon(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SetHeadIconCsReq, allocator);
|
||||
var rsp = protocol.SetHeadIconScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.current_head_icon_id = req.id;
|
||||
std.debug.print("SET HEAD ICON ID: {}\n", .{req.id});
|
||||
try session.send(CmdID.CmdSetHeadIconScRsp, rsp);
|
||||
}
|
||||
pub fn onSelectPhoneCase(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SelectPhoneCaseCsReq, allocator);
|
||||
var rsp = protocol.SelectPhoneCaseScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.cur_phone_case = req.phone_case_id;
|
||||
std.debug.print("SET PHONE CASE ID: {}\n", .{req.phone_case_id});
|
||||
try session.send(CmdID.CmdSelectPhoneCaseScRsp, rsp);
|
||||
}
|
146
gameserver/src/services/res_config.zig
Normal file
146
gameserver/src/services/res_config.zig
Normal file
|
@ -0,0 +1,146 @@
|
|||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const ResConfig = struct {
|
||||
planeID: u32,
|
||||
props: ArrayList(Props),
|
||||
monsters: ArrayList(Monsters),
|
||||
teleports: ArrayList(Teleports),
|
||||
};
|
||||
const Vector = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
};
|
||||
const Teleports = struct {
|
||||
anchorId: u32,
|
||||
groupId: u32,
|
||||
instId: u32,
|
||||
pos: Vector,
|
||||
rot: Vector,
|
||||
teleportId: u32,
|
||||
};
|
||||
const Monsters = struct {
|
||||
groupId: u32,
|
||||
instId: u32,
|
||||
eventId: u32,
|
||||
pos: Vector,
|
||||
rot: Vector,
|
||||
monsterId: u32,
|
||||
};
|
||||
const Props = struct {
|
||||
groupId: u32,
|
||||
instId: u32,
|
||||
propState: u32,
|
||||
pos: Vector,
|
||||
rot: Vector,
|
||||
propId: u32,
|
||||
};
|
||||
pub const SceneConfig = struct {
|
||||
scene_config: ArrayList(ResConfig),
|
||||
};
|
||||
|
||||
pub fn anchorLoader(allocator: Allocator, filename: []const u8) !SceneConfig {
|
||||
const file = try std.fs.cwd().openFile(filename, .{});
|
||||
defer file.close();
|
||||
|
||||
const file_size = try file.getEndPos();
|
||||
const buffer = try file.readToEndAlloc(allocator, file_size);
|
||||
defer allocator.free(buffer);
|
||||
|
||||
var json_tree = try std.json.parseFromSlice(std.json.Value, allocator, buffer, .{});
|
||||
defer json_tree.deinit();
|
||||
|
||||
const root = json_tree.value;
|
||||
const config: SceneConfig = try parseAnchor(root, allocator);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
fn parseAnchor(root: anytype, allocator: Allocator) !SceneConfig {
|
||||
var res_config = ArrayList(ResConfig).init(allocator);
|
||||
for (root.object.get("scene_config").?.array.items) |res_json| {
|
||||
var res = ResConfig{
|
||||
.planeID = @intCast(res_json.object.get("planeID").?.integer),
|
||||
.props = ArrayList(Props).init(allocator),
|
||||
.monsters = ArrayList(Monsters).init(allocator),
|
||||
.teleports = ArrayList(Teleports).init(allocator),
|
||||
};
|
||||
for (res_json.object.get("props").?.array.items) |scene_prop| {
|
||||
var prop = Props{
|
||||
.groupId = @intCast(scene_prop.object.get("groupId").?.integer),
|
||||
.instId = @intCast(scene_prop.object.get("instId").?.integer),
|
||||
.propState = @intCast(scene_prop.object.get("propState").?.integer),
|
||||
.pos = undefined,
|
||||
.rot = undefined,
|
||||
.propId = @intCast(scene_prop.object.get("propId").?.integer),
|
||||
};
|
||||
const pos_json = scene_prop.object.get("pos").?;
|
||||
prop.pos = Vector{
|
||||
.x = @intCast(pos_json.object.get("x").?.integer),
|
||||
.y = @intCast(pos_json.object.get("y").?.integer),
|
||||
.z = @intCast(pos_json.object.get("z").?.integer),
|
||||
};
|
||||
const rot_json = scene_prop.object.get("rot").?;
|
||||
prop.rot = Vector{
|
||||
.x = @intCast(rot_json.object.get("x").?.integer),
|
||||
.y = @intCast(rot_json.object.get("y").?.integer),
|
||||
.z = @intCast(rot_json.object.get("z").?.integer),
|
||||
};
|
||||
try res.props.append(prop);
|
||||
}
|
||||
for (res_json.object.get("monsters").?.array.items) |monster_json| {
|
||||
var monster = Monsters{
|
||||
.groupId = @intCast(monster_json.object.get("groupId").?.integer),
|
||||
.instId = @intCast(monster_json.object.get("instId").?.integer),
|
||||
.eventId = @intCast(monster_json.object.get("eventId").?.integer),
|
||||
.monsterId = @intCast(monster_json.object.get("monsterId").?.integer),
|
||||
.pos = undefined,
|
||||
.rot = undefined,
|
||||
};
|
||||
const pos_json = monster_json.object.get("pos").?;
|
||||
monster.pos = Vector{
|
||||
.x = @intCast(pos_json.object.get("x").?.integer),
|
||||
.y = @intCast(pos_json.object.get("y").?.integer),
|
||||
.z = @intCast(pos_json.object.get("z").?.integer),
|
||||
};
|
||||
const rot_json = monster_json.object.get("rot").?;
|
||||
monster.rot = Vector{
|
||||
.x = @intCast(rot_json.object.get("x").?.integer),
|
||||
.y = @intCast(rot_json.object.get("y").?.integer),
|
||||
.z = @intCast(rot_json.object.get("z").?.integer),
|
||||
};
|
||||
try res.monsters.append(monster);
|
||||
}
|
||||
for (res_json.object.get("teleports").?.array.items) |teleport_json| {
|
||||
var teleport = Teleports{
|
||||
.anchorId = @intCast(teleport_json.object.get("anchorId").?.integer),
|
||||
.groupId = @intCast(teleport_json.object.get("groupId").?.integer),
|
||||
.instId = @intCast(teleport_json.object.get("instId").?.integer),
|
||||
.teleportId = @intCast(teleport_json.object.get("teleportId").?.integer),
|
||||
.pos = undefined,
|
||||
.rot = undefined,
|
||||
};
|
||||
const pos_json = teleport_json.object.get("pos").?;
|
||||
teleport.pos = Vector{
|
||||
.x = @intCast(pos_json.object.get("x").?.integer),
|
||||
.y = @intCast(pos_json.object.get("y").?.integer),
|
||||
.z = @intCast(pos_json.object.get("z").?.integer),
|
||||
};
|
||||
const rot_json = teleport_json.object.get("rot").?;
|
||||
teleport.rot = Vector{
|
||||
.x = @intCast(rot_json.object.get("x").?.integer),
|
||||
.y = @intCast(rot_json.object.get("y").?.integer),
|
||||
.z = @intCast(rot_json.object.get("z").?.integer),
|
||||
};
|
||||
try res.teleports.append(teleport);
|
||||
}
|
||||
try res_config.append(res);
|
||||
}
|
||||
|
||||
return SceneConfig{
|
||||
.scene_config = res_config,
|
||||
};
|
||||
}
|
254
gameserver/src/services/scene.zig
Normal file
254
gameserver/src/services/scene.zig
Normal file
|
@ -0,0 +1,254 @@
|
|||
const std = @import("std");
|
||||
const protocol = @import("protocol");
|
||||
const Session = @import("../Session.zig");
|
||||
const Packet = @import("../Packet.zig");
|
||||
const Config = @import("config.zig");
|
||||
const Data = @import("../data.zig");
|
||||
const Res_config = @import("res_config.zig");
|
||||
const LineupManager = @import("../manager/lineup_mgr.zig").LineupManager;
|
||||
const SceneManager = @import("../manager/scene_mgr.zig").SceneManager;
|
||||
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const CmdID = protocol.CmdID;
|
||||
|
||||
const log = std.log.scoped(.scene_service);
|
||||
|
||||
pub fn onGetCurSceneInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var scene_manager = SceneManager.init(allocator);
|
||||
const scene_info = try scene_manager.createScene(20432, 20432001, 2043201, 1213);
|
||||
try session.send(CmdID.CmdGetCurSceneInfoScRsp, protocol.GetCurSceneInfoScRsp{
|
||||
.scene = scene_info,
|
||||
.retcode = 0,
|
||||
});
|
||||
}
|
||||
pub fn onSceneEntityMove(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SceneEntityMoveCsReq, allocator);
|
||||
for (req.entity_motion_list.items) |entity_motion| {
|
||||
if (entity_motion.motion) |motion| {
|
||||
if (entity_motion.entity_id > 99999 or entity_motion.entity_id == 0)
|
||||
log.debug("[POSITION] entity_id: {}, motion: {}", .{ entity_motion.entity_id, motion });
|
||||
}
|
||||
}
|
||||
try session.send(CmdID.CmdSceneEntityMoveScRsp, protocol.SceneEntityMoveScRsp{
|
||||
.retcode = 0,
|
||||
.entity_motion_list = req.entity_motion_list,
|
||||
.download_data = null,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn onEnterScene(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const entrance_config = try Config.loadMapEntranceConfig(allocator, "resources/MapEntrance.json");
|
||||
const req = try packet.getProto(protocol.EnterSceneCsReq, allocator);
|
||||
var lineup_mgr = LineupManager.init(allocator);
|
||||
const lineup = try lineup_mgr.createLineup();
|
||||
var scene_manager = SceneManager.init(allocator);
|
||||
var floorID: u32 = 0;
|
||||
var planeID: u32 = 0;
|
||||
var teleportID: u32 = 0;
|
||||
for (entrance_config.map_entrance_config.items) |entrConf| {
|
||||
if (entrConf.id == req.entry_id) {
|
||||
floorID = entrConf.floor_id;
|
||||
planeID = entrConf.plane_id;
|
||||
teleportID = req.teleport_id;
|
||||
}
|
||||
}
|
||||
const scene_info = try scene_manager.createScene(planeID, floorID, req.entry_id, teleportID);
|
||||
std.debug.print("ENTER SCENE ENTRY ID: {}, PLANE ID: {}, FLOOR ID: {}, TELEPORT ID: {}\n", .{ req.entry_id, planeID, floorID, teleportID });
|
||||
try session.send(CmdID.CmdEnterSceneByServerScNotify, protocol.EnterSceneByServerScNotify{
|
||||
.lineup = lineup,
|
||||
.reason = protocol.EnterSceneReason.ENTER_SCENE_REASON_NONE,
|
||||
.scene = scene_info,
|
||||
});
|
||||
try session.send(CmdID.CmdEnterSceneScRsp, protocol.EnterSceneScRsp{
|
||||
.retcode = 0,
|
||||
.game_story_line_id = req.game_story_line_id,
|
||||
.is_close_map = req.is_close_map,
|
||||
.content_id = req.content_id,
|
||||
.is_over_map = true,
|
||||
});
|
||||
}
|
||||
|
||||
//TODO FIX CURRENT SCENE MAP DISPLAY
|
||||
pub fn onGetSceneMapInfo(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.GetSceneMapInfoCsReq, allocator);
|
||||
const res_config = try Res_config.anchorLoader(allocator, "resources/res.json");
|
||||
const ranges = [_][2]usize{
|
||||
.{ 0, 101 },
|
||||
.{ 10000, 10051 },
|
||||
.{ 20000, 20001 },
|
||||
.{ 30000, 30020 },
|
||||
};
|
||||
const chest_list = &[_]protocol.ChestInfo{
|
||||
.{ .chest_type = protocol.ChestType.MAP_INFO_CHEST_TYPE_NORMAL },
|
||||
.{ .chest_type = protocol.ChestType.MAP_INFO_CHEST_TYPE_CHALLENGE },
|
||||
.{ .chest_type = protocol.ChestType.MAP_INFO_CHEST_TYPE_PUZZLE },
|
||||
};
|
||||
for (req.floor_id_list.items) |floor_id| {
|
||||
var rsp = protocol.GetSceneMapInfoScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.content_id = req.content_id;
|
||||
rsp.entry_story_line_id = req.entry_story_line_id;
|
||||
rsp.IGFIKGHLLNO = true;
|
||||
var map_info = protocol.SceneMapInfo.init(allocator);
|
||||
try map_info.chest_list.appendSlice(chest_list);
|
||||
map_info.entry_id = @intCast(floor_id);
|
||||
map_info.floor_id = @intCast(floor_id);
|
||||
map_info.cur_map_entry_id = @intCast(floor_id);
|
||||
for (res_config.scene_config.items) |sceneConf| {
|
||||
if (sceneConf.planeID != floor_id / 1000) continue;
|
||||
try map_info.unlock_teleport_list.ensureUnusedCapacity(sceneConf.teleports.items.len);
|
||||
try map_info.maze_prop_list.ensureUnusedCapacity(sceneConf.props.items.len);
|
||||
try map_info.maze_group_list.ensureUnusedCapacity(sceneConf.props.items.len);
|
||||
for (ranges) |range| {
|
||||
for (range[0]..range[1]) |i| {
|
||||
try map_info.lighten_section_list.append(@intCast(i));
|
||||
}
|
||||
}
|
||||
for (sceneConf.teleports.items) |teleConf| {
|
||||
try map_info.unlock_teleport_list.append(@intCast(teleConf.teleportId));
|
||||
}
|
||||
for (sceneConf.props.items) |propConf| {
|
||||
try map_info.maze_prop_list.append(protocol.MazePropState{
|
||||
.group_id = propConf.groupId,
|
||||
.config_id = propConf.instId,
|
||||
.state = propConf.propState,
|
||||
});
|
||||
try map_info.LMNGAHFNAON.append(protocol.OFCAIGDHPOH{
|
||||
.group_id = propConf.groupId,
|
||||
.config_id = propConf.instId,
|
||||
.state = propConf.propState,
|
||||
});
|
||||
try map_info.maze_group_list.append(protocol.MazeGroup{
|
||||
.NOBKEONAKLE = std.ArrayList(u32).init(allocator),
|
||||
.group_id = propConf.groupId,
|
||||
});
|
||||
}
|
||||
}
|
||||
try rsp.scene_map_info.append(map_info);
|
||||
try session.send(CmdID.CmdGetSceneMapInfoScRsp, rsp);
|
||||
}
|
||||
}
|
||||
pub fn onGetUnlockTeleport(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetUnlockTeleportScRsp.init(allocator);
|
||||
const res_config = try Res_config.anchorLoader(allocator, "resources/res.json");
|
||||
for (res_config.scene_config.items) |sceneCof| {
|
||||
for (sceneCof.teleports.items) |tp| {
|
||||
try rsp.unlock_teleport_list.append(tp.teleportId);
|
||||
}
|
||||
}
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdGetUnlockTeleportScRsp, rsp);
|
||||
}
|
||||
pub fn onEnterSection(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.EnterSectionCsReq, allocator);
|
||||
var rsp = protocol.EnterSectionScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
std.debug.print("ENTER SECTION Id: {}\n", .{req.section_id});
|
||||
try session.send(CmdID.CmdEnterSectionScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onGetEnteredScene(session: *Session, _: *const Packet, allocator: Allocator) !void {
|
||||
var rsp = protocol.GetEnteredSceneScRsp.init(allocator);
|
||||
var noti = protocol.EnteredSceneChangeScNotify.init(allocator);
|
||||
|
||||
const entrance_config = try Config.loadMapEntranceConfig(allocator, "resources/MapEntrance.json");
|
||||
for (entrance_config.map_entrance_config.items) |entrance| {
|
||||
try rsp.entered_scene_info_list.append(protocol.EnteredSceneInfo{
|
||||
.floor_id = entrance.floor_id,
|
||||
.plane_id = entrance.plane_id,
|
||||
});
|
||||
try noti.entered_scene_info_list.append(protocol.EnteredSceneInfo{
|
||||
.floor_id = entrance.floor_id,
|
||||
.plane_id = entrance.plane_id,
|
||||
});
|
||||
}
|
||||
rsp.retcode = 0;
|
||||
try session.send(CmdID.CmdEnteredSceneChangeScNotify, noti);
|
||||
try session.send(CmdID.CmdGetEnteredSceneScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onSceneEntityTeleport(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SceneEntityTeleportCsReq, allocator);
|
||||
var rsp = protocol.SceneEntityTeleportScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.entity_motion = req.entity_motion;
|
||||
std.debug.print("SCENE ENTITY TP ENTRY ID: {}\n", .{req.entry_id});
|
||||
try session.send(CmdID.CmdSceneEntityTeleportScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onGetFirstTalkNpc(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.GetFirstTalkNpcCsReq, allocator);
|
||||
var rsp = protocol.GetFirstTalkNpcScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
for (req.npc_id_list.items) |id| {
|
||||
try rsp.npc_meet_status_list.append(protocol.FirstNpcTalkInfo{ .npc_id = id, .is_meet = true });
|
||||
}
|
||||
try session.send(CmdID.CmdGetFirstTalkNpcScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onGetFirstTalkByPerformanceNp(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.GetFirstTalkByPerformanceNpcCsReq, allocator);
|
||||
var rsp = protocol.GetFirstTalkByPerformanceNpcScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
for (req.performance_id_list.items) |id| {
|
||||
try rsp.npc_meet_status_list.append(
|
||||
protocol.NpcMeetByPerformanceStatus{ .performance_id = id, .is_meet = true },
|
||||
);
|
||||
}
|
||||
try session.send(CmdID.CmdGetFirstTalkByPerformanceNpcScRsp, rsp);
|
||||
}
|
||||
|
||||
pub fn onGetNpcTakenReward(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.GetNpcTakenRewardCsReq, allocator);
|
||||
var rsp = protocol.GetNpcTakenRewardScRsp.init(allocator);
|
||||
const EventList = [_]u32{ 2136, 2134 };
|
||||
rsp.retcode = 0;
|
||||
rsp.npc_id = req.npc_id;
|
||||
try rsp.talk_event_list.appendSlice(&EventList);
|
||||
try session.send(CmdID.CmdGetNpcTakenRewardScRsp, rsp);
|
||||
}
|
||||
pub fn onUpdateGroupProperty(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.UpdateGroupPropertyCsReq, allocator);
|
||||
var rsp = protocol.UpdateGroupPropertyScRsp.init(allocator);
|
||||
rsp.retcode = 0;
|
||||
rsp.floor_id = req.floor_id;
|
||||
rsp.group_id = req.group_id;
|
||||
rsp.dimension_id = req.dimension_id;
|
||||
rsp.JAIBIEEKHEG = req.JAIBIEEKHEG;
|
||||
try session.send(CmdID.CmdUpdateGroupPropertyScRsp, rsp);
|
||||
}
|
||||
pub fn onChangePropTimeline(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.ChangePropTimelineInfoCsReq, allocator);
|
||||
try session.send(CmdID.CmdChangePropTimelineInfoScRsp, protocol.ChangePropTimelineInfoScRsp{
|
||||
.retcode = 0,
|
||||
.prop_entity_id = req.prop_entity_id,
|
||||
});
|
||||
}
|
||||
pub fn onDeactivateFarmElement(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.DeactivateFarmElementCsReq, allocator);
|
||||
std.debug.print("DEACTIVATE FARM ELEMENT ENTITY ID: {}\n", .{req.entity_id});
|
||||
try session.send(CmdID.CmdDeactivateFarmElementScRsp, protocol.DeactivateFarmElementScRsp{
|
||||
.retcode = 0,
|
||||
.entity_id = req.entity_id,
|
||||
});
|
||||
}
|
||||
pub fn onSetGroupCustomSaveData(session: *Session, packet: *const Packet, allocator: Allocator) !void {
|
||||
const req = try packet.getProto(protocol.SetGroupCustomSaveDataCsReq, allocator);
|
||||
//switch (req.AAMHHECOCOI) {
|
||||
// .Owned => |val| {
|
||||
// std.debug.print("CUSTOM SAVE DATA REQ: {s}\n", .{val.str});
|
||||
// },
|
||||
// .Const => |val| {
|
||||
// std.debug.print("CUSTOM SAVE DATA REQ: {s}\n", .{val});
|
||||
// },
|
||||
// .Empty => {
|
||||
// std.debug.print("CUSTOM SAVE DATA REQ: <empty string>\n", .{});
|
||||
// },
|
||||
//}
|
||||
try session.send(CmdID.CmdSetGroupCustomSaveDataScRsp, protocol.SetGroupCustomSaveDataScRsp{
|
||||
.retcode = 0,
|
||||
.group_id = req.group_id,
|
||||
.entry_id = req.entry_id,
|
||||
});
|
||||
}
|
34
hotfix.json
Normal file
34
hotfix.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"OSBETAWin3.2.51": {
|
||||
"asset_bundle_url": "https://autopatchos.starrails.com/asb/BetaLive/output_9961450_404865fc6856_fbf8b526e6b08c",
|
||||
"ex_resource_url": "https://autopatchos.starrails.com/design_data/BetaLive/output_9984498_2b39fa0086e4_1f081bc40d1782",
|
||||
"ifix_url": "https://autopatchos.starrails.com/ifix/BetaLive/output_0_40d2ce0253",
|
||||
"ifix_version": "0",
|
||||
"lua_url": "https://autopatchos.starrails.com/lua/BetaLive/output_9961575_227d4559d8e3_cd27ed7ca2bbfd",
|
||||
"lua_version": ""
|
||||
},
|
||||
"OSBETAWin3.2.52": {
|
||||
"asset_bundle_url": "https://autopatchos.starrails.com/asb/BetaLive/output_10025177_f10d2880371c_719811bc00424c",
|
||||
"ex_resource_url": "https://autopatchos.starrails.com/design_data/BetaLive/output_10037027_be14d3e01696_5aa1cd3547cbdb",
|
||||
"ifix_url": "https://autopatchos.starrails.com/ifix/BetaLive/output_0_40d2ce0253_6d871f8bca6eb4",
|
||||
"ifix_version": "0",
|
||||
"lua_url": "https://autopatchos.starrails.com/lua/BetaLive/output_10025298_1dc728a6c8ee_1128f068b506d4",
|
||||
"lua_version": ""
|
||||
},
|
||||
"OSBETAWin3.2.53": {
|
||||
"asset_bundle_url": "https://autopatchos.starrails.com/asb/BetaLive/output_10104345_a5535dc0c779_a36b870100988f",
|
||||
"ex_resource_url": "https://autopatchos.starrails.com/design_data/BetaLive/output_10128229_1abd7f8c3047_3cb3e1bffdb636",
|
||||
"ifix_url": "https://autopatchos.starrails.com/ifix/BetaLive/output_0_40d2ce0253_6d871f8bca6eb4",
|
||||
"ifix_version": "0",
|
||||
"lua_url": "https://autopatchos.starrails.com/lua/BetaLive/output_10104505_31a450a7e7a3_0793e9a5426e39",
|
||||
"lua_version": ""
|
||||
},
|
||||
"CNBETAWin3.3.51": {
|
||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10451237_a3aa836fce75_f560b891c0d21e",
|
||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10459782_ced8509d61c9_cdbde1049f2207",
|
||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10429797_be4a832b1c47_f58faff155c2c4",
|
||||
"ifix_version": "0",
|
||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10434495_6bff50432edd_1641e3e19f1244",
|
||||
"lua_version": ""
|
||||
}
|
||||
}
|
18
protocol/build.zig
Normal file
18
protocol/build.zig
Normal file
|
@ -0,0 +1,18 @@
|
|||
const std = @import("std");
|
||||
const protobuf = @import("protobuf");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const protobuf_dep = b.dependency("protobuf", .{
|
||||
.optimize = optimize,
|
||||
.target = target,
|
||||
});
|
||||
|
||||
const protocol = b.addModule("protocol", .{
|
||||
.root_source_file = b.path("src/root.zig"),
|
||||
});
|
||||
//
|
||||
protocol.addImport("protobuf", protobuf_dep.module("protobuf"));
|
||||
}
|
15
protocol/build.zig.zon
Normal file
15
protocol/build.zig.zon
Normal file
|
@ -0,0 +1,15 @@
|
|||
.{
|
||||
.name = "protocol",
|
||||
.version = "0.0.0",
|
||||
.dependencies = .{
|
||||
.protobuf = .{
|
||||
.url = "https://github.com/Arwalk/zig-protobuf/archive/7c49ed66e029c9c7e6253b3d6d256118745550a4.tar.gz",
|
||||
.hash = "122063ee7ff32a3c1aefd91a46a9fc23df0571949c3a02e2f44d39afbad0b53018a3",
|
||||
},
|
||||
},
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
},
|
||||
}
|
51292
protocol/src/protocol.pb.zig
Normal file
51292
protocol/src/protocol.pb.zig
Normal file
File diff suppressed because it is too large
Load diff
1949
protocol/src/root.zig
Normal file
1949
protocol/src/root.zig
Normal file
File diff suppressed because it is too large
Load diff
2134
resources/ActivityConfig.json
Normal file
2134
resources/ActivityConfig.json
Normal file
File diff suppressed because it is too large
Load diff
798
resources/AvatarPlayerIcon.json
Normal file
798
resources/AvatarPlayerIcon.json
Normal file
|
@ -0,0 +1,798 @@
|
|||
{
|
||||
"player_icon_config": [
|
||||
{
|
||||
"ID": 201001,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1001.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1001
|
||||
},
|
||||
{
|
||||
"ID": 201002,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1002.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1002
|
||||
},
|
||||
{
|
||||
"ID": 201003,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1003.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1003
|
||||
},
|
||||
{
|
||||
"ID": 201004,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1004.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1004
|
||||
},
|
||||
{
|
||||
"ID": 201005,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1005.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1005
|
||||
},
|
||||
{
|
||||
"ID": 201006,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1006.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1006
|
||||
},
|
||||
{
|
||||
"ID": 201008,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1008.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1008
|
||||
},
|
||||
{
|
||||
"ID": 201009,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1009.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1009
|
||||
},
|
||||
{
|
||||
"ID": 201013,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1013.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1013
|
||||
},
|
||||
{
|
||||
"ID": 201101,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1101.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1101
|
||||
},
|
||||
{
|
||||
"ID": 201102,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1102.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1102
|
||||
},
|
||||
{
|
||||
"ID": 201103,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1103.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1103
|
||||
},
|
||||
{
|
||||
"ID": 201104,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1104.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1104
|
||||
},
|
||||
{
|
||||
"ID": 201105,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1105.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1105
|
||||
},
|
||||
{
|
||||
"ID": 201106,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1106.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1106
|
||||
},
|
||||
{
|
||||
"ID": 201107,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1107.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1107
|
||||
},
|
||||
{
|
||||
"ID": 201108,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1108.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1108
|
||||
},
|
||||
{
|
||||
"ID": 201109,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1109.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1109
|
||||
},
|
||||
{
|
||||
"ID": 201110,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1110.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1110
|
||||
},
|
||||
{
|
||||
"ID": 201111,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1111.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1111
|
||||
},
|
||||
{
|
||||
"ID": 201203,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1203.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1203
|
||||
},
|
||||
{
|
||||
"ID": 201204,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1204.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1204
|
||||
},
|
||||
{
|
||||
"ID": 201205,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1205.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 1205
|
||||
},
|
||||
{
|
||||
"ID": 201206,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1206.png",
|
||||
"AvatarID": 1206
|
||||
},
|
||||
{
|
||||
"ID": 208001,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/8001.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 8001
|
||||
},
|
||||
{
|
||||
"ID": 208002,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/8002.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 8002
|
||||
},
|
||||
{
|
||||
"ID": 208003,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/8003.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 8003
|
||||
},
|
||||
{
|
||||
"ID": 208004,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/8004.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 8004
|
||||
},
|
||||
{
|
||||
"ID": 208005,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/8005.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 8005
|
||||
},
|
||||
{
|
||||
"ID": 208006,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/8006.png",
|
||||
"IsVisible": true,
|
||||
"AvatarID": 8006
|
||||
},
|
||||
{
|
||||
"ID": 201201,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1201.png",
|
||||
"AvatarID": 1201
|
||||
},
|
||||
{
|
||||
"ID": 201202,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1202.png",
|
||||
"AvatarID": 1202
|
||||
},
|
||||
{
|
||||
"ID": 201207,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1207.png",
|
||||
"AvatarID": 1207
|
||||
},
|
||||
{
|
||||
"ID": 201208,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1208.png",
|
||||
"AvatarID": 1208
|
||||
},
|
||||
{
|
||||
"ID": 201209,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1209.png",
|
||||
"AvatarID": 1209
|
||||
},
|
||||
{
|
||||
"ID": 201210,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1210.png",
|
||||
"AvatarID": 1210
|
||||
},
|
||||
{
|
||||
"ID": 201211,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1211.png",
|
||||
"AvatarID": 1211
|
||||
},
|
||||
{
|
||||
"ID": 201212,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1212.png",
|
||||
"AvatarID": 1212
|
||||
},
|
||||
{
|
||||
"ID": 201213,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1213.png",
|
||||
"AvatarID": 1213
|
||||
},
|
||||
{
|
||||
"ID": 201214,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1214.png",
|
||||
"AvatarID": 1214
|
||||
},
|
||||
{
|
||||
"ID": 201215,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1215.png",
|
||||
"AvatarID": 1215
|
||||
},
|
||||
{
|
||||
"ID": 201112,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1112.png",
|
||||
"AvatarID": 1112
|
||||
},
|
||||
{
|
||||
"ID": 201301,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1301.png",
|
||||
"AvatarID": 1301
|
||||
},
|
||||
{
|
||||
"ID": 201302,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1302.png",
|
||||
"AvatarID": 1302
|
||||
},
|
||||
{
|
||||
"ID": 201217,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1217.png",
|
||||
"AvatarID": 1217
|
||||
},
|
||||
{
|
||||
"ID": 201303,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1303.png",
|
||||
"AvatarID": 1303
|
||||
},
|
||||
{
|
||||
"ID": 201304,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1304.png",
|
||||
"AvatarID": 1304
|
||||
},
|
||||
{
|
||||
"ID": 201305,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1305.png",
|
||||
"AvatarID": 1305
|
||||
},
|
||||
{
|
||||
"ID": 201307,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1307.png",
|
||||
"AvatarID": 1307
|
||||
},
|
||||
{
|
||||
"ID": 201308,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1308.png",
|
||||
"AvatarID": 1308
|
||||
},
|
||||
{
|
||||
"ID": 201309,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1309.png",
|
||||
"AvatarID": 1309
|
||||
},
|
||||
{
|
||||
"ID": 201312,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1312.png",
|
||||
"AvatarID": 1312
|
||||
},
|
||||
{
|
||||
"ID": 201314,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1314.png",
|
||||
"AvatarID": 1314
|
||||
},
|
||||
{
|
||||
"ID": 201315,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1315.png",
|
||||
"AvatarID": 1315
|
||||
},
|
||||
{
|
||||
"ID": 201310,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1310.png",
|
||||
"AvatarID": 1310
|
||||
},
|
||||
{
|
||||
"ID": 201306,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1306.png",
|
||||
"AvatarID": 1306
|
||||
},
|
||||
{
|
||||
"ID": 201218,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1218.png",
|
||||
"AvatarID": 1218
|
||||
},
|
||||
{
|
||||
"ID": 201224,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1224.png",
|
||||
"AvatarID": 1224
|
||||
},
|
||||
{
|
||||
"ID": 201313,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1313.png",
|
||||
"AvatarID": 1313
|
||||
},
|
||||
{
|
||||
"ID": 201221,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1221.png",
|
||||
"AvatarID": 1221
|
||||
},
|
||||
{
|
||||
"ID": 201220,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1220.png",
|
||||
"AvatarID": 1220
|
||||
},
|
||||
{
|
||||
"ID": 201317,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1317.png",
|
||||
"AvatarID": 1317
|
||||
},
|
||||
{
|
||||
"ID": 201223,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1223.png",
|
||||
"AvatarID": 1223
|
||||
},
|
||||
{
|
||||
"ID": 201222,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1222.png",
|
||||
"AvatarID": 1222
|
||||
},
|
||||
{
|
||||
"ID": 201225,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1225.png",
|
||||
"AvatarID": 1225
|
||||
},
|
||||
{
|
||||
"ID": 201402,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1402.png",
|
||||
"AvatarID": 1402
|
||||
},
|
||||
{
|
||||
"ID": 201401,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1401.png",
|
||||
"AvatarID": 1401
|
||||
},
|
||||
{
|
||||
"ID": 201403,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1403.png",
|
||||
"AvatarID": 1403
|
||||
},
|
||||
{
|
||||
"ID": 208007,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/8007.png",
|
||||
"AvatarID": 8007
|
||||
},
|
||||
{
|
||||
"ID": 201404,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1404.png",
|
||||
"AvatarID": 1404
|
||||
},
|
||||
{
|
||||
"ID": 208008,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/8008.png",
|
||||
"AvatarID": 8008
|
||||
},
|
||||
{
|
||||
"ID": 201407,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1407.png",
|
||||
"AvatarID": 1407
|
||||
},
|
||||
{
|
||||
"ID": 201408,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1408.png",
|
||||
"AvatarID": 1408
|
||||
},
|
||||
{
|
||||
"ID": 201405,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1405.png",
|
||||
"AvatarID": 1405
|
||||
},
|
||||
{
|
||||
"ID": 201409,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1409.png",
|
||||
"AvatarID": 1409
|
||||
},
|
||||
{
|
||||
"ID": 201406,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1406.png",
|
||||
"AvatarID": 1406
|
||||
},
|
||||
{
|
||||
"ID": 200001,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/UI_Message_Contacts_Anonymous.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200101,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200101.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200102,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200102.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200103,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200103.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200104,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200104.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200105,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200105.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200106,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200106.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200107,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200107.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200108,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200108.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200109,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200109.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200110,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200110.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200111,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200111.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200112,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200112.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200113,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200113.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200114,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200114.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200115,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200115.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200116,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200116.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200117,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200117.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200118,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200118.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200119,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200119.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200120,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200120.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200121,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200121.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200122,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200122.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200123,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200123.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200124,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200124.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200125,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200125.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200126,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200126.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200127,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200127.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200128,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200128.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200129,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200129.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200130,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200130.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200131,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200131.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200132,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200132.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200133,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200133.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200134,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200134.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200135,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200135.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200136,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200136.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200137,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200137.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200138,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200138.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200139,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200139.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200140,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200140.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200141,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200141.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 200142,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/200142.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202001,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202001.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202002,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202002.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202003,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202003.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202004,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202004.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202005,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202005.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202006,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202006.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202007,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202007.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202008,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202008.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202009,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202009.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202010,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202010.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202011,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202011.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202012,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202012.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202013,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202013.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202014,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202014.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202015,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202015.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202016,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202016.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202017,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202017.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202018,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202018.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202019,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202019.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202020,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202020.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202022,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202022.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202023,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202023.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202024,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202024.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202025,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202025.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202028,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202028.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202029,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/AvatarSkin/1100101.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202031,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202031.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202033,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202033.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202034,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/AvatarSkin/1131001.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202035,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202035.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202036,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202036.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 202037,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Series/202037.png",
|
||||
"IsVisible": true
|
||||
},
|
||||
{
|
||||
"ID": 201014,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1014.png",
|
||||
"AvatarID": 1014
|
||||
},
|
||||
{
|
||||
"ID": 201015,
|
||||
"ImagePath": "SpriteOutput/AvatarRoundIcon/Avatar/1015.png",
|
||||
"AvatarID": 1015
|
||||
}
|
||||
]
|
||||
}
|
31884
resources/ChallengeMazeConfig.json
Normal file
31884
resources/ChallengeMazeConfig.json
Normal file
File diff suppressed because it is too large
Load diff
49274
resources/MainMission.json
Normal file
49274
resources/MainMission.json
Normal file
File diff suppressed because it is too large
Load diff
6891
resources/MapEntrance.json
Normal file
6891
resources/MapEntrance.json
Normal file
File diff suppressed because it is too large
Load diff
4423
resources/MazePlane.json
Normal file
4423
resources/MazePlane.json
Normal file
File diff suppressed because it is too large
Load diff
294444
resources/StageConfig.json
Normal file
294444
resources/StageConfig.json
Normal file
File diff suppressed because it is too large
Load diff
14259
resources/TutorialData.json
Normal file
14259
resources/TutorialData.json
Normal file
File diff suppressed because it is too large
Load diff
13349
resources/TutorialGuideGroup.json
Normal file
13349
resources/TutorialGuideGroup.json
Normal file
File diff suppressed because it is too large
Load diff
466085
resources/res.json
Normal file
466085
resources/res.json
Normal file
File diff suppressed because it is too large
Load diff
4
run.bat
Normal file
4
run.bat
Normal file
|
@ -0,0 +1,4 @@
|
|||
@echo
|
||||
|
||||
start zig build run-dispatch
|
||||
start zig build run-gameserver
|
Loading…
Reference in a new issue