First push

This commit is contained in:
xeon 2024-06-25 21:30:33 +03:00
parent f0211138f5
commit 43fd9302d6
26 changed files with 38824 additions and 0 deletions

22
.gitignore vendored Normal file
View file

@ -0,0 +1,22 @@
# This file is for zig-specific build artifacts.
# If you have OS-specific or editor-specific files to ignore,
# such as *.swp or .DS_Store, put those in your global
# ~/.gitignore and put this in your ~/.gitconfig:
#
# [core]
# excludesfile = ~/.gitignore
.zig-cache/
zig-out/
/release/
/debug/
/build/
/build-*/
/docgen_tmp/
# Although this was renamed to .zig-cache, let's leave it here for a few
# releases to make it less annoying to work with multiple branches.
zig-cache/
protocol/StarRail.proto
protocol/nameTranslation.txt

51
build.zig Normal file
View file

@ -0,0 +1,51 @@
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);
}

15
build.zig.zon Normal file
View file

@ -0,0 +1,15 @@
.{
.name = "YunliSR",
.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 = .{""},
}

35
dispatch/build.zig Normal file
View file

@ -0,0 +1,35 @@
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,
});
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);
}

28
dispatch/build.zig.zon Normal file
View file

@ -0,0 +1,28 @@
.{
.name = "dispatch",
.version = "0.0.1",
.minimum_zig_version = "0.13.0",
// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
.httpz = .{
.url = "https://github.com/karlseguin/http.zig/archive/406fb00f8c43fe9b2da0f32f428675755c67d054.tar.gz",
.hash = "12209e87663712928c6ae1c690e65df15a796e970e5d18f5e4e05f0eb10404883d23",
},
.protocol = .{
.path = "../protocol",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
// For example...
//"LICENSE",
//"README.md",
},
}

View file

@ -0,0 +1,48 @@
const std = @import("std");
const httpz = @import("httpz");
pub fn onShieldLogin(_: *httpz.Request, res: *httpz.Response) !void {
std.log.debug("onShieldLogin", .{});
try res.json(.{
.retcode = 0,
.message = "OK",
.data = .{
.account = .{
.area_code = "**",
.email = "reversedrooms@xeondev.com",
.country = "RU",
.is_email_verify = "1",
.token = "mostsecuretokenever",
.uid = "1337",
},
},
}, .{});
}
pub fn onComboTokenReq(_: *httpz.Request, res: *httpz.Response) !void {
std.log.debug("onComboTokenReq", .{});
try res.json(.{
.retcode = 0,
.message = "OK",
.data = .{
.account_type = 1,
.open_id = "1337",
.combo_id = "1337",
.combo_token = "mostsecuretokenever",
.heartbeat = false,
.data = "{\"guest\": false}",
},
}, .{});
}
pub fn onRiskyApiCheck(_: *httpz.Request, res: *httpz.Response) !void {
std.log.debug("onRiskyApiCheck", .{});
try res.json(.{
.retcode = 0,
.message = "OK",
.data = .{ .id = "" },
}, .{});
}

56
dispatch/src/dispatch.zig Normal file
View file

@ -0,0 +1,56 @@
const std = @import("std");
const httpz = @import("httpz");
const protocol = @import("protocol");
const Base64Encoder = @import("std").base64.standard.Encoder;
pub fn onQueryDispatch(_: *httpz.Request, res: *httpz.Response) !void {
std.log.debug("onQueryDispatch", .{});
var proto = protocol.GlobalDispatchData.init(res.arena);
proto.retcode = 0;
try proto.server_list.append(.{
.name = .{ .Const = "YunliSR" },
.display_name = .{ .Const = "YunliSR" },
.env_type = .{ .Const = "2" },
.title = .{ .Const = "YunliSR" },
.dispatch_url = .{ .Const = "http://127.0.0.1:21000/query_gateway" },
});
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(_: *httpz.Request, res: *httpz.Response) !void {
std.log.debug("onQueryGateway", .{});
var proto = protocol.Gateserver.init(res.arena);
proto.retcode = 0;
proto.use_tcp = true;
proto.port = 23301;
proto.ip = .{ .Const = "127.0.0.1" };
proto.lua_version = .{ .Const = "7327274" };
proto.ifix_version = .{ .Const = "0" };
proto.lua_url = .{ .Const = "https://autopatchos.starrails.com/lua/BetaLive/output_7327274_d12d75929650" };
proto.asset_bundle_url = .{ .Const = "https://autopatchos.starrails.com/asb/BetaLive/output_7327119_c52eec0f6a92" };
proto.ex_resource_url = .{ .Const = "https://autopatchos.starrails.com/design_data/BetaLive/output_7349339_419592cb2562" };
proto.MCANJEHAEKO = true;
proto.PGMFEHFKLBG = true;
proto.NNPPEAAIHAK = true;
proto.LGPAAPCPBMD = true;
proto.GNFPFKJHIDJ = true;
proto.FKFKCDJNHFL = true;
proto.AOEKIKFKMGA = true;
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;
}

22
dispatch/src/main.zig Normal file
View file

@ -0,0 +1,22 @@
const std = @import("std");
const httpz = @import("httpz");
const protocol = @import("protocol");
const authentication = @import("authentication.zig");
const dispatch = @import("dispatch.zig");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
var server = try httpz.Server().init(allocator, .{ .port = 21000 });
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/combo/granter/login/v2/login", authentication.onComboTokenReq);
try server.listen();
}

28
gameserver/build.zig Normal file
View 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
View 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",
},
}

75
gameserver/src/Packet.zig Normal file
View file

@ -0,0 +1,75 @@
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);
}

View file

@ -0,0 +1,54 @@
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();
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);
std.log.debug("sent packet with id {}", .{cmd_id});
}
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);
std.log.debug("sent EMPTY packet with id {}", .{cmd_id});
}

View file

@ -0,0 +1,93 @@
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 battle = @import("services/battle.zig");
const login = @import("services/login.zig");
const lineup = @import("services/lineup.zig");
const mission = @import("services/mission.zig");
const scene = @import("services/scene.zig");
const misc = @import("services/misc.zig");
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const CmdID = protocol.CmdID;
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.CmdGetAvatarDataCsReq, avatar.onGetAvatarData },
.{ CmdID.CmdGetMissionStatusCsReq, mission.onGetMissionStatus },
.{ CmdID.CmdGetCurLineupDataCsReq, lineup.onGetCurLineupData },
.{ CmdID.CmdGetCurSceneInfoCsReq, scene.onGetCurSceneInfo },
.{ CmdID.CmdSceneEntityMoveCsReq, scene.onSceneEntityMove },
.{ CmdID.CmdStartCocoonStageCsReq, battle.onStartCocoonStage },
.{ CmdID.CmdPVEBattleResultCsReq, battle.onPVEBattleResult },
};
const DummyCmdList = [_]struct { CmdID, CmdID }{
.{ CmdID.CmdGetBasicInfoCsReq, CmdID.CmdGetBasicInfoScRsp },
.{ CmdID.CmdGetMultiPathAvatarInfoCsReq, CmdID.CmdGetMultiPathAvatarInfoScRsp },
.{ 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.CmdGetActivityScheduleConfigCsReq, CmdID.CmdGetActivityScheduleConfigScRsp },
.{ CmdID.CmdGetMissionDataCsReq, CmdID.CmdGetMissionDataScRsp },
.{ CmdID.CmdGetMissionEventDataCsReq, CmdID.CmdGetMissionEventDataScRsp },
.{ CmdID.CmdGetQuestDataCsReq, CmdID.CmdGetQuestDataScRsp },
.{ CmdID.CmdGetCurChallengeCsReq, CmdID.CmdGetCurChallengeScRsp },
.{ 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.CmdSyncClientResVersionCsReq, CmdID.CmdSyncClientResVersionScRsp },
.{ 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.CmdGetCurBattleInfoCsReq, CmdID.CmdGetCurBattleInfoScRsp },
.{ CmdID.CmdHeliobusActivityDataCsReq, CmdID.CmdHeliobusActivityDataScRsp },
.{ CmdID.CmdGetEnteredSceneCsReq, CmdID.CmdGetEnteredSceneScRsp },
.{ CmdID.CmdGetAetherDivideInfoCsReq, CmdID.CmdGetAetherDivideInfoScRsp },
.{ CmdID.CmdGetMapRotationDataCsReq, CmdID.CmdGetMapRotationDataScRsp },
.{ CmdID.CmdGetRogueCollectionCsReq, CmdID.CmdGetRogueCollectionScRsp },
.{ CmdID.CmdGetRogueExhibitionCsReq, CmdID.CmdGetRogueExhibitionScRsp },
.{ CmdID.CmdPlayerReturnInfoQueryCsReq, CmdID.CmdPlayerReturnInfoQueryScRsp },
.{ CmdID.CmdPlayerLoginFinishCsReq, CmdID.CmdPlayerLoginFinishScRsp },
.{ CmdID.CmdGetLevelRewardTakenListCsReq, CmdID.CmdGetLevelRewardTakenListScRsp },
.{ CmdID.CmdGetMainMissionCustomValueCsReq, CmdID.CmdGetMainMissionCustomValueScRsp },
};
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());
std.log.debug("packet {} was handled", .{cmd_id});
return;
}
}
inline for (DummyCmdList) |pair| {
if (pair[0] == cmd_id) {
try session.send_empty(pair[1]);
return;
}
}
std.log.warn("packet {} was ignored", .{cmd_id});
}

10
gameserver/src/main.zig Normal file
View file

@ -0,0 +1,10 @@
const std = @import("std");
const network = @import("network.zig");
const handlers = @import("handlers.zig");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
try network.listen(allocator);
}

View file

@ -0,0 +1,36 @@
const std = @import("std");
const Session = @import("Session.zig");
const Allocator = std.mem.Allocator;
pub fn listen(allocator: Allocator) !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 session = try allocator.create(Session);
session.* = Session.init(conn.address, conn.stream, allocator);
const thread = try std.Thread.spawn(.{}, runSession, .{session});
thread.detach();
}
}
fn runSession(s: *Session) void {
std.log.info("new connection from {}", .{s.address});
if (s.run()) |_| {
std.log.info("client from {} disconnected", .{s.address});
} else |err| {
std.log.err("session disconnected with an error: {}", .{err});
}
s.allocator.destroy(s);
}

View file

@ -0,0 +1,31 @@
const std = @import("std");
const protocol = @import("protocol");
const CmdID = protocol.CmdID;
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Allocator = std.mem.Allocator;
const AllAvatars = [_]u32{
1001, 1002, 1003, 1004, 1005, 1006, 1008, 1009, 1013, 1101, 1102, 1103, 1104, 1105, 1106, 1107,
1108, 1109, 1110, 1111, 1112, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211,
1212, 1213, 1214, 1215, 1217, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1312,
1314, 1315, 1221, 1218,
};
pub fn onGetAvatarData(session: *Session, packet: *const Packet, allocator: Allocator) !void {
const req = try packet.getProto(protocol.GetAvatarDataCsReq, allocator);
var rsp = protocol.GetAvatarDataScRsp.init(allocator);
rsp.is_all = req.is_get_all;
for (AllAvatars) |id| {
var avatar = protocol.Avatar.init(allocator);
avatar.base_avatar_id = id;
avatar.level = 80;
avatar.promotion = 6;
avatar.rank = 6;
try rsp.avatar_list.append(avatar);
}
try session.send(CmdID.CmdGetAvatarDataScRsp, rsp);
}

View file

@ -0,0 +1,50 @@
const std = @import("std");
const protocol = @import("protocol");
const CmdID = protocol.CmdID;
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Allocator = std.mem.Allocator;
pub fn onStartCocoonStage(session: *Session, packet: *const Packet, allocator: Allocator) !void {
const req = try packet.getProto(protocol.StartCocoonStageCsReq, allocator);
var avatar = protocol.BattleAvatar.init(allocator);
avatar.id = 1221;
avatar.hp = 10000;
avatar.sp = .{ .sp_cur = 10000, .sp_need = 10000 };
avatar.level = 80;
avatar.rank = 6;
avatar.promotion = 6;
avatar.avatar_type = .AVATAR_FORMAL_TYPE;
var battle = protocol.SceneBattleInfo.init(allocator);
for (0..req.wave) |_| {
const monster = protocol.SceneMonsterInfo{ .monster_id = 3024020 };
var monster_wave = protocol.SceneMonsterWave.init(allocator);
try monster_wave.monster_list.append(monster);
try battle.monster_wave_list.append(monster_wave);
}
try battle.battle_avatar_list.append(avatar);
battle.battle_id = 1;
battle.stage_id = 201012311;
battle.logic_random_seed = @intCast(@mod(std.time.timestamp(), 0xFFFFFFFF));
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 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;
try session.send(CmdID.CmdPVEBattleResultScRsp, rsp);
}

View file

@ -0,0 +1,26 @@
const std = @import("std");
const protocol = @import("protocol");
const CmdID = protocol.CmdID;
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Allocator = std.mem.Allocator;
pub fn onGetCurLineupData(session: *Session, _: *const Packet, allocator: Allocator) !void {
const avatar = protocol.LineupAvatar{
.id = 1221,
.slot = 0,
.satiety = 0,
.hp = 10000,
.avatar_type = protocol.AvatarType.AVATAR_FORMAL_TYPE,
.sp = .{ .sp_cur = 10000, .sp_need = 10000 },
};
var lineup = protocol.LineupInfo.init(allocator);
lineup.name = .{ .Const = "Squad 1" };
try lineup.avatar_list.append(avatar);
try session.send(CmdID.CmdGetCurLineupDataScRsp, protocol.GetCurLineupDataScRsp{
.retcode = 0,
.lineup = lineup,
});
}

View file

@ -0,0 +1,32 @@
const std = @import("std");
const protocol = @import("protocol");
const CmdID = protocol.CmdID;
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Allocator = std.mem.Allocator;
pub fn onPlayerGetToken(session: *Session, _: *const Packet, allocator: Allocator) !void {
var rsp = protocol.PlayerGetTokenScRsp.init(allocator);
rsp.retcode = 0;
rsp.uid = 1337;
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 = 240;
basic_info.level = 5;
basic_info.nickname = .{ .Const = "xeondev" };
var rsp = protocol.PlayerLoginScRsp.init(allocator);
rsp.retcode = 0;
rsp.login_random = req.login_random;
rsp.stamina = 240;
rsp.basic_info = basic_info;
try session.send(CmdID.CmdPlayerLoginScRsp, rsp);
}

View file

@ -0,0 +1,26 @@
const std = @import("std");
const protocol = @import("protocol");
const CmdID = protocol.CmdID;
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Allocator = std.mem.Allocator;
const B64Decoder = std.base64.standard.Decoder;
pub fn onPlayerHeartBeat(session: *Session, packet: *const Packet, allocator: Allocator) !void {
const req = try packet.getProto(protocol.PlayerHeartBeatCsReq, allocator);
const downloadDataBin = "CDMQuQoa1AFDUy5Vbml0eUVuZ2luZS5HYW1lT2JqZWN0LkZpbmQoIlVJUm9vdC9BYm92ZURpYWxvZy9CZXRhSGludERpYWxvZyhDbG9uZSkiKTpHZXRDb21wb25lbnRJbkNoaWxkcmVuKHR5cGVvZihDUy5SUEcuQ2xpZW50LkxvY2FsaXplZFRleHQpKS50ZXh0ID0gIll1bmxpU1IgaXMgYSBmcmVlIGFuZCBvcGVuIHNvdXJjZSBzb2Z0d2FyZS4gZGlzY29yZC5nZy9yZXZlcnNlZHJvb21zIg==";
const size = try B64Decoder.calcSizeForSlice(downloadDataBin);
const buf = try allocator.alloc(u8, size);
_ = try B64Decoder.decode(buf, downloadDataBin);
const data = try protocol.ClientDownloadData.decode(buf, allocator);
const rsp = protocol.PlayerHeartBeatScRsp{
.retcode = 0,
.client_time_ms = req.client_time_ms,
.server_time_ms = @intCast(std.time.timestamp()),
.download_data = data,
};
try session.send(CmdID.CmdPlayerHeartBeatScRsp, rsp);
}

View file

@ -0,0 +1,96 @@
const std = @import("std");
const protocol = @import("protocol");
const CmdID = protocol.CmdID;
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Allocator = std.mem.Allocator;
const FinishedMainMissionIdList = [_]u32{
1000101, 1000111, 1000112, 1000113, 1000114, 1000201, 1000202, 1000203, 1000204, 1000300,
1000301, 1000302, 1000303, 1000304, 1000400, 1000401, 1000402, 1000410, 1000500, 1000501,
1000502, 1000503, 1000504, 1000505, 1000510, 1000511, 1010001, 1010002, 1010101, 1010201,
1010202, 1010203, 1010204, 1010205, 1010206, 1010301, 1010302, 1010303, 1010401, 1010405,
1010402, 1010403, 1010500, 1010501, 1010502, 1010503, 1010601, 1010602, 1010700, 1010701,
1010801, 1010802, 1010901, 1010902, 1011001, 1011002, 1011003, 1011100, 1011101, 1011102,
1011103, 1011201, 1011202, 1011301, 1011400, 1011401, 1011402, 1011403, 1011501, 1011502,
1011503, 1020101, 1020201, 1020302, 1020301, 1020400, 1020401, 1020402, 1020403, 1020501,
1020601, 1020701, 1020702, 1020801, 1020901, 1021001, 1021101, 1021201, 1021301, 1021401,
1021501, 1021601, 2000001, 2000002, 2000003, 2000004, 2000100, 2000101, 2000131, 2000132,
2000133, 2000110, 2000111, 2000301, 2000103, 2000112, 2000108, 2000104, 2000102, 2000105,
2000106, 2000107, 2000313, 2000314, 2000109, 2000113, 2000116, 2000118, 2000119, 2000120,
2000122, 2000302, 2000303, 2000304, 2000305, 2000310, 2000311, 2000312, 2000320, 2000701,
2000702, 2000703, 2000704, 2000705, 2000706, 2000707, 2010005, 2010301, 2010302, 2011103,
2011104, 2011409, 2010401, 2010402, 2010405, 2010502, 2010503, 2010701, 2010708, 2010709,
2010720, 2010730, 2010731, 2010732, 2010733, 2010734, 2010735, 2010904, 2011101, 2011102,
2011105, 2011301, 2011302, 2011303, 2011501, 2011502, 2010909, 2010910, 2011901, 2011902,
2011903, 2011904, 2011905, 2011906, 2020301, 2020302, 2020304, 2020316, 2020317, 2020318,
2020319, 2020401, 2020402, 2020403, 2020404, 2020405, 2020406, 2020407, 2020303, 2020103,
2020104, 2020105, 2020106, 2020107, 2020108, 2020109, 2020110, 2020201, 2020202, 2020203,
2020204, 2000201, 2000202, 2000203, 2000204, 2000205, 2000206, 2000207, 2000208, 2000209,
2000211, 2000212, 2010500, 2010501, 2010705, 2010706, 2010901, 2010902, 2010903, 2010702,
2010703, 2011400, 2011401, 2011406, 2011402, 2011403, 2011404, 2011405, 2011407, 2011408,
2011410, 2010905, 2010906, 2010907, 2010908, 2010911, 2010912, 2020305, 2020306, 2020309,
2020307, 2020308, 2020701, 2020702, 2020313, 2020314, 2020315, 6020101, 6020201, 6020202,
2020801, 2020802, 2020901, 2021601, 2021602, 3000201, 3000202, 3000203, 3000211, 3000212,
3000213, 3000301, 3000302, 3000303, 3000522, 3000523, 3000524, 3000525, 3000526, 3000527,
3000601, 3000602, 3000603, 3000604, 3000701, 3000702, 3000703, 3000704, 3000705, 3000800,
3000801, 3000802, 3000803, 3010102, 3010103, 3010104, 3010105, 3010201, 3010202, 3010203,
3010204, 3010205, 3011011, 3011012, 3011013, 3011014, 3011111, 3011112, 3011113, 3011114,
3011201, 3011202, 3011203, 3011204, 3011205, 3011206, 3011207, 3011208, 3011401, 3011402,
3011403, 3011404, 3011405, 3011406, 3011407, 3011408, 3011501, 3011502, 3011503, 3011504,
3011505, 3011601, 3011602, 3011603, 3011604, 3011605, 3011606, 3011607, 3011608, 3011609,
3011610, 3012001, 4020101, 4020102, 4020103, 4020104, 4020105, 4020106, 4020107, 4020108,
4020109, 4020110, 4020111, 4020112, 4020113, 4020114, 4010105, 4010106, 4010107, 4010112,
4010113, 4010131, 4010115, 4010116, 4010121, 4010122, 4010123, 4010124, 4010125, 4010126,
4010127, 4010128, 4010133, 4010134, 4010135, 4010130, 4010136, 4010137, 4015101, 4015103,
4015102, 4015202, 4015203, 4015204, 4015301, 4015302, 4015303, 4030001, 4030002, 4030003,
4030004, 4030006, 4030007, 4030009, 4030010, 4040001, 4040002, 4040003, 4040004, 4040005,
4040006, 4040052, 4040007, 4040008, 4040051, 4040009, 4040010, 4040011, 4040012, 4040053,
4040014, 4040015, 4040017, 4040018, 4040019, 4040020, 4040021, 4040022, 4040023, 4040024,
4040100, 4040189, 4040190, 4040101, 4040151, 4040154, 4040102, 4040103, 4040153, 4040104,
4040152, 4040105, 4040106, 4040155, 4040107, 4040108, 4040109, 4040156, 4040157, 4040110,
4040114, 4040115, 4040158, 4040159, 4040160, 4040161, 4040162, 4040116, 4040169, 4040163,
4040164, 4040165, 4040166, 4040167, 4040168, 4040170, 4040171, 4040172, 4040173, 4040174,
4040175, 4040176, 4040177, 4040178, 4040179, 4040180, 4040181, 4040182, 4040183, 4040184,
4040185, 4040186, 4040117, 4040118, 4040119, 4040187, 4040120, 4040188, 4040121, 4040122,
4040123, 4040124, 4040125, 4040126, 4040127, 4040128, 4040129, 4040130, 4040201, 4040202,
4040203, 4040204, 4040205, 4040206, 4040207, 4040208, 4040290, 4040209, 4040210, 4040211,
4040212, 4040213, 4040214, 4040215, 4040216, 4040217, 4040218, 4040219, 4040220, 4040221,
4040222, 4040223, 4040224, 4040225, 4040226, 4040227, 4040228, 4040229, 4040230, 4040231,
4040240, 4040241, 4040242, 4040244, 4040245, 4040246, 4040247, 4050005, 4050007, 4050008,
4050009, 4050010, 4050011, 4050012, 4050013, 4050014, 4050015, 4050016, 4050017, 4050018,
4050019, 4050020, 4050021, 4050022, 4050023, 4050024, 4050025, 4050026, 4050027, 4050028,
4050029, 4050030, 4050031, 4050032, 4050033, 4050034, 4050035, 4050036, 4050037, 4072121,
4072122, 4072123, 4071311, 4071312, 4071313, 4071320, 4071321, 4071322, 4122100, 4122101,
4122102, 4122103, 4081311, 4081312, 4081313, 4081314, 4081315, 4081316, 4081317, 4081318,
8000001, 8000002, 8000101, 8000102, 8000104, 8000105, 8000131, 8000132, 8000133, 8000134,
8000135, 8000136, 8000137, 8000138, 8000139, 8000151, 8000152, 8000153, 8000154, 8000155,
8000156, 8000157, 8000158, 8000159, 8000161, 8000162, 8000170, 8000171, 8000172, 8000173,
8000174, 8000175, 8000177, 8000178, 8000180, 8000181, 8000183, 8000182, 8000185, 8000184,
8000186, 8000187, 8000188, 8000189, 8000201, 8000202, 8000203, 8000204, 8001201, 8001202,
8001203, 8001205, 8001206, 8001207, 8001208, 8001209, 8001211, 8001212, 8001213, 8001215,
8001216, 8001219, 8001220, 8001223, 8001224, 8001225, 8001226, 8001227, 8001204, 8001210,
8001214, 8001217, 8001218, 8001221, 8001222, 8001241, 8001242, 8001243, 8001244, 8001251,
8001252, 8001253, 8001254, 8001255, 8001261, 8001262, 8001263, 8001264, 8001265, 8001266,
8001267, 8001268, 8011401, 8002201, 8002202, 8002211, 8002212, 8002213, 8002214, 8002221,
8002222, 8002231, 8002232, 8002233, 8002234, 8012101, 8012102, 8012103, 8012104, 8012105,
8012106, 8012107, 8012401, 9999920,
};
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);
rsp.retcode = 0;
for (req.sub_mission_id_list.items) |id| {
try rsp.sub_mission_status_list.append(protocol.Mission{ .id = id, .status = protocol.MissionStatus.MISSION_FINISH, .progress = 1 });
}
for (req.mission_event_id_list.items) |id| {
try rsp.mission_event_status_list.append(protocol.Mission{ .id = id, .status = protocol.MissionStatus.MISSION_FINISH, .progress = 1 });
}
try rsp.finished_main_mission_id_list.appendSlice(&FinishedMainMissionIdList);
try session.send(CmdID.CmdGetMissionStatusScRsp, rsp);
}

View file

@ -0,0 +1,76 @@
const std = @import("std");
const protocol = @import("protocol");
const CmdID = protocol.CmdID;
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Allocator = std.mem.Allocator;
pub fn onGetCurSceneInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
var scene_info = protocol.SceneInfo.init(allocator);
scene_info.game_mode_type = 1;
scene_info.plane_id = 20101;
scene_info.floor_id = 20101001;
scene_info.entry_id = 2010101;
{ // Character
var scene_group = protocol.SceneGroupInfo.init(allocator);
scene_group.state = 1;
try scene_group.entity_list.append(.{
.entity = .{
.actor = .{
.base_avatar_id = 1221,
.avatar_type = .AVATAR_FORMAL_TYPE,
.uid = 1337,
.map_layer = 2,
},
},
.motion = .{ .pos = .{ .x = -2300, .y = 19365, .z = 3150 }, .rot = .{} },
});
try scene_info.scene_group_list.append(scene_group);
}
{ // Calyx prop
var scene_group = protocol.SceneGroupInfo.init(allocator);
scene_group.state = 1;
scene_group.group_id = 19;
var prop = protocol.ScenePropInfo.init(allocator);
prop.prop_id = 808;
prop.prop_state = 1;
try scene_group.entity_list.append(.{
.group_id = 19,
.inst_id = 300001,
.entity_id = 1337,
.entity = .{
.prop = prop,
},
.motion = .{ .pos = .{ .x = -570, .y = 19364, .z = 4480 }, .rot = .{} },
});
try scene_info.scene_group_list.append(scene_group);
}
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| {
std.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,
});
}

18
protocol/build.zig Normal file
View 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
View 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",
},
}

36306
protocol/src/protocol.pb.zig Normal file

File diff suppressed because it is too large Load diff

1557
protocol/src/root.zig Normal file

File diff suppressed because it is too large Load diff