mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-09-26 01:50:23 +00:00
Compare commits
201 Commits
Author | SHA1 | Date | |
---|---|---|---|
df655dfe29 | |||
c8c4ec7d01 | |||
458843958b | |||
958d4a79eb | |||
e86860baf7 | |||
![]() |
a8c88a9bd9 | ||
![]() |
038ce984c5 | ||
![]() |
361c069d0c | ||
![]() |
3876e0537e | ||
![]() |
8a481acdae | ||
e936cb9fac | |||
![]() |
589da3f714 | ||
266ca8b8c6 | |||
00c5e07f4f | |||
05d035717d | |||
f41bf0ace2 | |||
063d302bd5 | |||
7e9793bf90 | |||
![]() |
fa6b0b178c | ||
![]() |
dadf1c5bcf | ||
![]() |
359991e274 | ||
![]() |
260759c20b | ||
![]() |
1ff5694960 | ||
![]() |
be4c5a8072 | ||
![]() |
ef84ec8fca | ||
![]() |
11801c1f89 | ||
4f6c77be4f | |||
73c67a814d | |||
d7a41d40ab | |||
0aeac0f6f3 | |||
48b0866441 | |||
4ade533f40 | |||
1e344c2dd8 | |||
fdd0160248 | |||
5f10718315 | |||
![]() |
da293ba9b3 | ||
![]() |
437063d78a | ||
![]() |
b239fb9331 | ||
50431024c9 | |||
2a258a80f0 | |||
322bc46604 | |||
2551f74af1 | |||
![]() |
1af240fa34 | ||
a067975f27 | |||
72a811d6ab | |||
3b35e0017a | |||
4df812f996 | |||
67d899efe6 | |||
64accecc30 | |||
c8c2f4b05f | |||
3c43dd0193 | |||
9e9161083d | |||
![]() |
5cf7225f52 | ||
![]() |
5c8a0069fc | ||
64d4b1d26a | |||
9b0cb7f441 | |||
c48db0f9f9 | |||
e0c00bcdc8 | |||
6db1a7baf1 | |||
99e357d24e | |||
![]() |
57681cd669 | ||
c9badae526 | |||
![]() |
d3ca93a9b8 | ||
![]() |
6808365d48 | ||
4178945abe | |||
3e5101892b | |||
60be814e16 | |||
16c11dada0 | |||
260331715f | |||
b187d4b65f | |||
3b3ddf08ef | |||
41898bb6b7 | |||
dff710cf61 | |||
b79bc56b31 | |||
9aa9b76826 | |||
113ce0af07 | |||
6f1a72ca0f | |||
d964a83d6d | |||
d025b611a1 | |||
2f1358c124 | |||
c1b6ae8466 | |||
14bc368073 | |||
c5dacb4958 | |||
fb993f0c5d | |||
6d3868349d | |||
16bca39dae | |||
![]() |
afbf309c7e | ||
28ad1a0c25 | |||
![]() |
ff5f3966e3 | ||
55add82843 | |||
e99feb03d5 | |||
431448ffb7 | |||
8105d0aa88 | |||
acf358ef51 | |||
![]() |
0a8e96ebc4 | ||
756074cc62 | |||
51a8cc8bdf | |||
651ccba932 | |||
1281fdaaf0 | |||
561a809f33 | |||
0d27412d81 | |||
![]() |
1d792a21dd | ||
d6b96389be | |||
![]() |
6129c0b4e2 | ||
c9bf3d1896 | |||
88953541ef | |||
94b0dc724e | |||
0ff1f74cd3 | |||
35b424c531 | |||
2072bdcff7 | |||
![]() |
4f10ee0505 | ||
cd9fb6ec25 | |||
![]() |
56bf0db20d | ||
11fed7db10 | |||
35c622d8a2 | |||
43f2def80b | |||
0ac600e223 | |||
![]() |
5f65a84b02 | ||
78c493b461 | |||
f71e1349c1 | |||
cff382a8ce | |||
bbd6c5b532 | |||
![]() |
ab6df26f92 | ||
![]() |
786ee5f4f4 | ||
c5efbceca3 | |||
bf6c5d1b6b | |||
fdfa7b5776 | |||
f289c72f6f | |||
![]() |
7318d9b578 | ||
![]() |
caaffcbe3d | ||
3fe1a02200 | |||
cd19c54824 | |||
![]() |
88d08ffca7 | ||
![]() |
7a46f061ed | ||
![]() |
df18f3ccd1 | ||
1669ee3660 | |||
5d0b30b4cb | |||
![]() |
0041da795a | ||
![]() |
24be117e28 | ||
c7f9358ae5 | |||
eee1b52722 | |||
![]() |
e3d53e8dcf | ||
![]() |
b89df8d497 | ||
![]() |
faf73fc835 | ||
![]() |
aa2adcd9e2 | ||
![]() |
e044b4251a | ||
7b085e9c8b | |||
![]() |
da11220762 | ||
1425074ccb | |||
![]() |
c66ac111ab | ||
![]() |
32a37acd5a | ||
49fbdd2154 | |||
6857f50c30 | |||
![]() |
c827b5a1b6 | ||
![]() |
7f8e7dfa1c | ||
![]() |
09b21c54d3 | ||
![]() |
c549192f59 | ||
6843faeb8d | |||
b43628a19d | |||
b94f602537 | |||
![]() |
fa5f194cc7 | ||
fbc3c79aa2 | |||
93d973bf21 | |||
7cf239e3af | |||
![]() |
14d556976d | ||
af6158fbb2 | |||
c0abab39ae | |||
dff6e8c23b | |||
d6e1f57c23 | |||
9f3f9bb9c3 | |||
0654500df3 | |||
a0065c2050 | |||
![]() |
795107a274 | ||
42597c2a7a | |||
![]() |
bb1ce5c28d | ||
![]() |
e75049fc98 | ||
![]() |
1ec4634f69 | ||
4d9072a752 | |||
a0d59419f1 | |||
94cb89dd6b | |||
ba81db97ef | |||
ec84d6ca58 | |||
b8f7d2efc6 | |||
e7b58c4b32 | |||
0f5be27c97 | |||
8328ebf4f3 | |||
a17b72b0b3 | |||
95e454232a | |||
fafde9348e | |||
f2059c9ce1 | |||
![]() |
e5274045b0 | ||
![]() |
941d98cc07 | ||
![]() |
3a892de7c7 | ||
8e87a3f102 | |||
24d30a05bf | |||
b2325eb308 | |||
47b76b422c | |||
208f4b3bbd | |||
78e096a411 | |||
2e9e265cba | |||
8400a15262 |
23
.editorconfig
Normal file
23
.editorconfig
Normal file
@@ -0,0 +1,23 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# 4 space indentation
|
||||
[*.cpp,*.hpp]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# Tabs in makefile
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
# Don't enforce anything in contrib
|
||||
[/src/contrib/**]
|
||||
end_of_line = unset
|
||||
insert_final_newline = unset
|
||||
indent_style = unset
|
||||
indent_style = unset
|
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,4 +1,13 @@
|
||||
.vscode
|
||||
.vscode/
|
||||
bin/*
|
||||
notes.txt
|
||||
config.ini
|
||||
config.ini
|
||||
*.o
|
||||
tags
|
||||
*~
|
||||
CMakeFiles/
|
||||
CMakeCache.txt
|
||||
build/
|
||||
.vs/
|
||||
.idea/
|
||||
*.db
|
||||
|
9
.vimrc
Normal file
9
.vimrc
Normal file
@@ -0,0 +1,9 @@
|
||||
" vim configuration file
|
||||
|
||||
" You will need to put 'set exrc' and 'set secure' into your main .vimrc file,
|
||||
" in which case this file will be loaded automatically, but *only* if you
|
||||
" start vim in this dir. Alternatively you can just load it directly with
|
||||
" ':so .vimrc' every time.
|
||||
set tabstop=4
|
||||
set shiftwidth=4
|
||||
set expandtab
|
48
CMakeLists.txt
Normal file
48
CMakeLists.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(OpenFusion)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# OpenFusion supports multiple packet/struct versions
|
||||
# 104 is the default version to build which can be changed
|
||||
# For example: cmake -B build -DPROTOCOL_VERSION=728
|
||||
set(PROTOCOL_VERSION 104 CACHE STRING "The packet version to build")
|
||||
|
||||
add_compile_definitions(PROTOCOL_VERSION=${PROTOCOL_VERSION})
|
||||
|
||||
# Disallow in-source builds
|
||||
if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(FATAL_ERROR "In-source builds not allowed. Please refer to the wiki for more information. Please remove the CMakeFiles folder and the CMakeCache.txt file.")
|
||||
endif()
|
||||
|
||||
# Output binaries to the bin folder in the source directory
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
|
||||
|
||||
# Put CMake targets (ALL_BUILD/ZERO_CHECK) into a folder
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# Set the OpenFusion project as the default startup project for VS
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT openfusion)
|
||||
|
||||
if (WIN32)
|
||||
# Set the output binary name to winfusion to match the regular Makefile
|
||||
set(BIN_NAME winfusion)
|
||||
else()
|
||||
set(BIN_NAME fusion)
|
||||
endif()
|
||||
|
||||
include_directories(src)
|
||||
|
||||
file(GLOB_RECURSE SOURCES src/**.cpp src/**.hpp src/**.c src/**.h)
|
||||
|
||||
add_executable(openfusion ${SOURCES})
|
||||
|
||||
set_target_properties(openfusion PROPERTIES OUTPUT_NAME ${BIN_NAME})
|
||||
|
||||
# Use pthreads if not generating a VS solution or MinGW makefile (because MinGW will prefer Win32 threads)
|
||||
# Checking if the compiler ID is MSVC will allow us to open the project as a CMake project in VS.
|
||||
# It's not something you should do, but it's there if you need it...
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Visual Studio" AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_GENERATOR MATCHES "MinGW Makefiles")
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(openfusion pthread)
|
||||
endif()
|
83
CONTRIBUTING.md
Normal file
83
CONTRIBUTING.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Contributing
|
||||
|
||||
If you want to contribute to OpenFusion's development, that's great!
|
||||
We'd appreciate it if you already had some programming experience, as well as experience with software version control using git.
|
||||
|
||||
If you've never used git before, please take the time to research it yourself.
|
||||
There is an abundance of online resources for getting started with git.
|
||||
|
||||
If, however, you have no experience programming, this type of project may not be the best one to start with.
|
||||
OpenFusion is written in C++, which really isn't the best language to start with, as it has many extremely subtle pitfalls with potentially catastrophic consequences that are often very hard for an inexperienced programmer to detect and avoid.
|
||||
This is compounded by the fact that this is a server, which means it's a long-running, multithreaded process exposed to the network, decoding an externally-imposed binary protocol -- written in C++.
|
||||
A bad combination.
|
||||
|
||||
With that out of the way, the rest of this document will serve to address the matter of clean commits in Pull Requests.
|
||||
|
||||
## Repository cleanliness
|
||||
|
||||
The commit history in a git repository is important.
|
||||
Unlike some other version control systems, git allows developers to destructively edit history so as to enjoy the benefits of both frequent "saves" (as in, having the ability to record corrections as soon as you make them) and clean commits which perfectly encapsulate a given change.
|
||||
Each developer has their own preferred way of doing things, of course, but in general one commit should represent one functional change in the codebase as a whole.
|
||||
Developers should be able to view a project's commit history and easily understand how the project has evolved over time.
|
||||
|
||||
Achieving this is often daunting for new users of git.
|
||||
I know of two intermediate-level resources (that is, for after you've learned the basics of git) I can recommend for understanding how to properly manage your repository's history -- [think-like-a-git.net](http://think-like-a-git.net/) and [git-rebase.io](https://git-rebase.io/).
|
||||
Both are pretty short reads and following them will get you up to speed with branches and the rebasing thereof.
|
||||
|
||||
I will now cover a few examples of the complications people have encountered contributing to this project, how to understand them, overcome them and henceforth avoid them.
|
||||
|
||||
## Dirty pull requests
|
||||
|
||||
Many Pull Requests OpenFusion receives fail to present a clean set of commits to merge.
|
||||
These are generally either:
|
||||
|
||||
* Dozens of quick-fix commits the author made while working on their contribution
|
||||
* Countless useless merge commits generated while trying to re-synchronize with the upstream repository
|
||||
|
||||
Few developers are fine with having their commit histories utterly destroyed by merging these changes in.
|
||||
Many projects, when presented with such Pull Requests, will flat-out reject them or demand the author clean them up first before they can be accepted.
|
||||
|
||||
Cpunch, however, chooses to accept them anyway, but squashes them into the repository with the "rebase" merge strategy, instead of a regular merge.
|
||||
Whereas a regular merge creates a "merge commit" which unites two branches together, a rebase instead *reconstructs* the commits from one branch onto the other, creating *different commits* with possibly the same contents.
|
||||
|
||||
If you read the above links, you'll note that this isn't exactly a perfect solution either, since rewriting history in public is usually a bad idea, but because these changes were originally only visible to the PR author, it is only they that will need to rebase their fork to re-sync with the upstream repository.
|
||||
The obvious issue, then, is that the people submitting dirty PRs are the exact people who don't *know* how to rebase their fork to continue submitting their work cleanly.
|
||||
So they end up creating countless merge commits when pulling upstream on top of their own incompatible histories, and then submitting those merge commits in their PRs and the cycle continues.
|
||||
|
||||
## The details
|
||||
|
||||
A git commit is uniquely identified by its SHA1 hash.
|
||||
Its hash is generated from its contents, as well as the hash(es) of its parent commit(s).
|
||||
(Most commits have one parent. Merge commits almost always have two, but octopus merges can have any number of parents.)
|
||||
That means that even if two commits are exactly the same in terms of content, they're not the same commit if their parent commits differ (ex. if they've been rebased).
|
||||
So if you keep issuing `git pull`s after upstream has merged a rebased version of your PR, you will never re-synchronize with it, and will instead construct an alternate history polluted by pointless merge commits.
|
||||
|
||||
## The solution
|
||||
|
||||
If you already have a messed-up fork and you have no changes on it that you're afraid to lose, the solution is simple:
|
||||
|
||||
* Ensure your `upstream` remote is up to date with `git fetch upstream`
|
||||
* Make sure you're on master (`git branch master`)
|
||||
* Set your master branch to the latest commit with `git reset --hard upstream/master`
|
||||
* Propagate the change to your GitHub fork with `git push -f origin master`
|
||||
|
||||
And you're good to go.
|
||||
If you do have some committed changes that haven't yet been merged upstream, you should probably save them on another branch (called "backup" or something) with `git checkout -b backup`.
|
||||
|
||||
If you do end up messing something up, don't worry, it most likely isn't really lost and `git reflog` is your friend.
|
||||
(You can checkout an arbitrary commit, and make it into its own branch with `git checkout -b BRANCH` or set a pre-exisitng branch to it with `git reset --hard COMMIT`)
|
||||
|
||||
## Avoiding the problem
|
||||
|
||||
When working on a changeset you want to submit back upstream, don't do it on the main branch.
|
||||
Create a work branch just for your changeset with `git checkout -b work`.
|
||||
That way you can always keep master in sync with upstream with `git pull --ff-only upstream master`.
|
||||
(`--ff-only` can be left out. If you find that git want you to make a merge commit, just back out of it by saving an empty commit message, then fix whatever the cause was.)
|
||||
|
||||
* If upstream gets new changes before you've had a chance to submit yours, just update master, create a new branch from your work branch and rebase your new work branch on master (such that your up-to-date changeset is now on the new work branch) and submit that one for your PR
|
||||
* If you end up making a few ugly fixup commits, use `git rebase --interactive` to clean them up (on a new branch) before submitting your changeset
|
||||
* If you get told to change something in the PR before it's merged, but after you've pushed it to your GitHub fork, rebase your changes locally, then force-push them onto the your fork's PR branch with `git push -f origin work1` or so
|
||||
|
||||
Creating new branches for the rebase isn't strictly necessary since you can always return a branch to its previous state with `git reflog`.
|
||||
|
||||
For moving uncommited changes around between branches, `git stash` is a real blessing.
|
22
LICENSE.md
22
LICENSE.md
@@ -1,9 +1,21 @@
|
||||
The OpenFusion MIT except Marlorn License
|
||||
MIT License
|
||||
|
||||
Copyright 2020 Seth Stubbs
|
||||
Copyright (c) 2020 Seth Stubbs
|
||||
|
||||
Excluding the individual known as "MarlornWS" and their associates, permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
139
Makefile
139
Makefile
@@ -1,23 +1,126 @@
|
||||
# makefile for OpenFusion
|
||||
|
||||
OBJS = src/*.cpp # source files to compile
|
||||
CC = clang++ # using GNU C++ compiler
|
||||
WIN_CC = x86_64-w64-mingw32-g++ # using GNU C++ compiler
|
||||
|
||||
CC=clang
|
||||
CXX=clang++
|
||||
# -w suppresses all warnings (the part that's commented out helps me find memory leaks, it ruins performance though!)
|
||||
COMPILER_FLAGS = -std=c++17 -o3 -static #-g3 -fsanitize=address
|
||||
WIN_COMPILER_FLAGS = -std=c++17 -o3 -static #-g3 -fsanitize=address
|
||||
CFLAGS=-O3 #-g3 -fsanitize=address
|
||||
CXXFLAGS=-Wall -Wno-unknown-pragmas -std=c++17 -O2 -DPROTOCOL_VERSION=$(PROTOCOL_VERSION) #-g3 -fsanitize=address
|
||||
LDFLAGS=-lpthread -ldl #-g3 -fsanitize=address
|
||||
# specifies the name of our exectuable
|
||||
SERVER=bin/fusion
|
||||
|
||||
#LINKER_FLAGS specifies the libraries we're linking against (NONE, this is a single header library.)
|
||||
LINKER_FLAGS = -lpthread
|
||||
WIN_LINKER_FLAGS = -lws2_32 -lwsock32
|
||||
# assign protocol version
|
||||
# this can be overriden by ex. make PROTOCOL_VERSION=728
|
||||
PROTOCOL_VERSION?=104
|
||||
|
||||
#OBJ_NAME specifies the name of our exectuable
|
||||
OBJ_NAME = bin/fusion # location of output for build
|
||||
WIN_OBJ_NAME = bin/winfusion.exe # location of output for build
|
||||
# Windows-specific
|
||||
WIN_CC=x86_64-w64-mingw32-gcc
|
||||
WIN_CXX=x86_64-w64-mingw32-g++
|
||||
WIN_CFLAGS=-O3 #-g3 -fsanitize=address
|
||||
WIN_CXXFLAGS=-Wall -Wno-unknown-pragmas -std=c++17 -O3 -fno-tree-dce -fno-inline-small-functions -DPROTOCOL_VERSION=$(PROTOCOL_VERSION) #-g3 -fsanitize=address
|
||||
WIN_LDFLAGS=-static -lws2_32 -lwsock32 #-g3 -fsanitize=address
|
||||
WIN_SERVER=bin/winfusion.exe
|
||||
|
||||
all: $(OBJS)
|
||||
$(CC) $(OBJS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME)
|
||||
CSRC=\
|
||||
src/contrib/sqlite/sqlite3.c\
|
||||
src/contrib/bcrypt/bcrypt.c\
|
||||
src/contrib/bcrypt/crypt_blowfish.c\
|
||||
src/contrib/bcrypt/crypt_gensalt.c\
|
||||
src/contrib/bcrypt/wrapper.c\
|
||||
|
||||
windows: $(OBJS)
|
||||
$(WIN_CC) $(OBJS) $(WIN_COMPILER_FLAGS) $(WIN_LINKER_FLAGS) -o $(WIN_OBJ_NAME)
|
||||
CXXSRC=\
|
||||
src/ChatManager.cpp\
|
||||
src/CombatManager.cpp\
|
||||
src/CNLoginServer.cpp\
|
||||
src/CNProtocol.cpp\
|
||||
src/CNShardServer.cpp\
|
||||
src/CNShared.cpp\
|
||||
src/CNStructs.cpp\
|
||||
src/Database.cpp\
|
||||
src/Defines.cpp\
|
||||
src/main.cpp\
|
||||
src/MissionManager.cpp\
|
||||
src/NanoManager.cpp\
|
||||
src/ItemManager.cpp\
|
||||
src/NPCManager.cpp\
|
||||
src/Player.cpp\
|
||||
src/PlayerManager.cpp\
|
||||
src/settings.cpp\
|
||||
src/TransportManager.cpp\
|
||||
|
||||
# headers (for timestamp purposes)
|
||||
CHDR=\
|
||||
src/contrib/sqlite/sqlite3.h\
|
||||
src/contrib/sqlite/sqlite_orm.h\
|
||||
src/contrib/bcrypt/bcrypt.h\
|
||||
src/contrib/bcrypt/crypt_blowfish.h\
|
||||
src/contrib/bcrypt/crypt_gensalt.h\
|
||||
src/contrib/bcrypt/ow-crypt.h\
|
||||
src/contrib/bcrypt/winbcrypt.h\
|
||||
|
||||
CXXHDR=\
|
||||
src/contrib/bcrypt/BCrypt.hpp\
|
||||
src/contrib/INIReader.hpp\
|
||||
src/contrib/JSON.hpp\
|
||||
src/ChatManager.hpp\
|
||||
src/CombatManager.hpp\
|
||||
src/CNLoginServer.hpp\
|
||||
src/CNProtocol.hpp\
|
||||
src/CNShardServer.hpp\
|
||||
src/CNShared.hpp\
|
||||
src/CNStructs.hpp\
|
||||
src/Database.hpp\
|
||||
src/Defines.hpp\
|
||||
src/contrib/INIReader.hpp\
|
||||
src/contrib/JSON.hpp\
|
||||
src/MissionManager.hpp\
|
||||
src/NanoManager.hpp\
|
||||
src/ItemManager.hpp\
|
||||
src/NPCManager.hpp\
|
||||
src/Player.hpp\
|
||||
src/PlayerManager.hpp\
|
||||
src/settings.hpp\
|
||||
src/TransportManager.hpp\
|
||||
|
||||
COBJ=$(CSRC:.c=.o)
|
||||
CXXOBJ=$(CXXSRC:.cpp=.o)
|
||||
|
||||
OBJ=$(COBJ) $(CXXOBJ)
|
||||
|
||||
HDR=$(CHDR) $(CXXHDR)
|
||||
|
||||
all: $(SERVER)
|
||||
|
||||
windows: $(SERVER)
|
||||
|
||||
# assign Windows-specific values if targeting Windows
|
||||
windows : CC=$(WIN_CC)
|
||||
windows : CXX=$(WIN_CXX)
|
||||
windows : CFLAGS=$(WIN_CFLAGS)
|
||||
windows : CXXFLAGS=$(WIN_CXXFLAGS)
|
||||
windows : LDFLAGS=$(WIN_LDFLAGS)
|
||||
windows : SERVER=$(WIN_SERVER)
|
||||
|
||||
.SUFFIX: .o .c .cpp .h .hpp
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) -c $(CXXFLAGS) -o $@ $<
|
||||
|
||||
# header timestamps are a prerequisite for OF object files
|
||||
$(CXXOBJ): $(CXXHDR)
|
||||
|
||||
$(SERVER): $(OBJ) $(CHDR) $(CXXHDR)
|
||||
mkdir -p bin
|
||||
$(CXX) $(OBJ) $(LDFLAGS) -o $(SERVER)
|
||||
|
||||
.PHONY: all windows clean nuke
|
||||
|
||||
# only gets rid of OpenFusion objects, so we don't need to
|
||||
# recompile the libs every time
|
||||
clean:
|
||||
rm -f src/*.o $(SERVER) $(WIN_SERVER)
|
||||
|
||||
# gets rid of all compiled objects, including the libraries
|
||||
nuke:
|
||||
rm -f $(OBJ) $(SERVER) $(WIN_SERVER)
|
||||
|
48
README.md
48
README.md
@@ -1,4 +1,7 @@
|
||||
# OpenFusion
|
||||

|
||||
|
||||
[](https://ci.appveyor.com/project/OpenFusionProject/openfusion)
|
||||
[](https://discord.gg/DYavckB)
|
||||
|
||||
OpenFusion is a landwalker server for FusionFall. It currently supports versions `beta-20100104` and `beta-20100728` of the original game.
|
||||
|
||||
@@ -8,17 +11,21 @@ Further documentation pending.
|
||||
|
||||
tl;dr:
|
||||
|
||||
1. Download the client+server bundle from [here](...).
|
||||
1. Download the client+server bundle from [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.0/OpenFusion.zip).
|
||||
2. Run `FreeClient/installUnity.bat` once
|
||||
|
||||
From then on, any time you want to run the "game":
|
||||
|
||||
3. Run `OpenFusion/winfusion.exe`
|
||||
3. Run `Server/winfusion.exe`
|
||||
4. Run `FreeClient/OpenFusionClient.exe`
|
||||
|
||||
Currently the client by default connects to a public server hosted by Cake. Change the loginInfo.php to point to your own server if you want to host your own.
|
||||
|
||||
You have two randomized characters available to you on the Character Selection screen, one boy, one girl.
|
||||
You can also make your own character and play through the tutorial. The tutorial can be skipped by pressing the ~ key.
|
||||
|
||||
If you want, [compiled binaries (artifacts) for each new commit can be found on AppVeyor.](https://ci.appveyor.com/project/OpenFusionProject/openfusion)
|
||||
|
||||
For a more detailed overview of the game's architecture and how to configure it, read the following sections.
|
||||
|
||||
## Architecture
|
||||
@@ -54,7 +61,7 @@ When the player clicks "ENTER THE GAME" (or completes the tutorial), the login s
|
||||
|
||||
## Configuration
|
||||
|
||||
You can change the ports the FusionFall server listens on in `OpenFusion/config.ini`. Make sure the login server port is in sync with `loginInfo.php`.
|
||||
You can change the ports the FusionFall server listens on in `Server/config.ini`. Make sure the login server port is in sync with `loginInfo.php`.
|
||||
The shard port needs no such synchronization.
|
||||
You can also configure the distance at which you'll be able to see other players, though by default it's already as high as you'll want it.
|
||||
|
||||
@@ -63,14 +70,26 @@ This just works if you're all under the same LAN, but if you want to play over t
|
||||
|
||||
If you're in a region in which Turner's CDN doesn't still have the game's assets cached, you won't be able to play the game in its default configuration.
|
||||
You'll need to obtain the necessary assets elsewhere and set up your own local web server to host them, because unlike web browsers, the game itself cannot interpret the `file://` schema, and will thus need the assets hosted on an actual HTTP server.
|
||||
Don't forget to point `assetInfo.php` to where you're hosting the assets and change the `src` param of both the `<embed>` tag and the `<object>` tag in `FreeClient/resources/files/index.html` to where you're hosting the `.unity3d` entrypoint.
|
||||
Don't forget to point `assetInfo.php` to where you're hosting the assets and change the `src` param of both the `<embed>` tag and the `<object>` tag in `FreeClient/resources/app/files/index.html` to where you're hosting the `.unity3d` entrypoint.
|
||||
|
||||
If you change `loginInfo.php` or `assetInfo.php`, make sure not to put any newline characters (or any other whitespace) at the end of the file(s).
|
||||
Some modern IDEs/text editors do this automatically. If all else fails, use Notepad.
|
||||
|
||||
## Compiling
|
||||
|
||||
OpenFusion can be compiled from source using the included makefile. to compile for windows (on a *nix system) use `make windows`, otherwise to compile it for the current platform you're on just run `make`
|
||||
You have two choices for compiling OpenFusion: the included Makefile and the included CMakeLists file.
|
||||
|
||||
### Makefile
|
||||
|
||||
A detailed compilation guide is available for Windows users in the wiki [using MinGW-w64 and MSYS2](https://github.com/OpenFusionProject/OpenFusion/wiki/Compilation-on-Windows). Otherwise, to compile it for the current platform you're on, just run `make` with the correct build tools installed (currently make and clang).
|
||||
|
||||
### CMake
|
||||
|
||||
A detailed guide is available [in the wiki](https://github.com/OpenFusionProject/OpenFusion/wiki/Compilation-with-CMake-or-Visual-Studio) for people using regular old CMake or the version of CMake that comes with Visual Studio. tl;dr: `cmake -B build`
|
||||
|
||||
## Contributing
|
||||
|
||||
If you'd like to contribute to this project, please read [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## "Gameplay"
|
||||
|
||||
@@ -81,7 +100,22 @@ It's what's called a landwalker; enough of the server has been implemented to al
|
||||
|
||||
To make your landwalking experience more pleasant, you can make use of a few admin commands to get around easier:
|
||||
|
||||
### Movement commands
|
||||
* A `/speed` of around 2400 or 3000 is nice.
|
||||
* A `/jump` of about 50 will send you soaring
|
||||
* [This map](res/dong_number_map.png) (credit to Danny O) is useful for `/warp` coordinates.
|
||||
* `/goto` is useful for more precise teleportation (ie. for getting into Infected Zones, etc.).
|
||||
* `/goto` is useful for more precise teleportation (ie. for getting into Infected Zones, etc.).
|
||||
|
||||
### Item commands
|
||||
* `/itemN [type] [itemId] [amount]`
|
||||
(Refer to the [item list](https://docs.google.com/spreadsheets/d/1mpoJ9iTHl_xLI4wQ_9UvIDYNcsDYscdkyaGizs43TCg/))
|
||||
|
||||
### Nano commands
|
||||
* `/nano [id] (1-36)`
|
||||
* `/nano_equip [id] (1-36) [slot] (0-2)`
|
||||
* `/nano_unequip [slot] (0-2)`
|
||||
* `/nano_active [slot] (0-2)`
|
||||
|
||||
## Accounts
|
||||
|
||||
A basic account system has been added, when logging in if the username doesn't exist in the database, a new account with the provided password will be made and you'll be automatically logged in. Otherwise a login attempt will be made. A username must be between 4 and 32 characters, and a password must be between 8 and 32 characters otherwise the account will be rejected. Characters currently save only upon creation, any items add/traded will not be saved.
|
79
appveyor.yml
Normal file
79
appveyor.yml
Normal file
@@ -0,0 +1,79 @@
|
||||
version: 'openfusion-{branch}-{build}'
|
||||
|
||||
image:
|
||||
- Visual Studio 2019
|
||||
- Ubuntu2004
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
||||
for:
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Ubuntu2004
|
||||
build_script:
|
||||
- ps: |
|
||||
$versions = "104", "728"
|
||||
|
||||
foreach ($version in $versions) {
|
||||
Write-Output "Cleaning old output"
|
||||
Invoke-Expression "make clean"
|
||||
if ($LASTEXITCODE -ne "0") {
|
||||
Write-Error "make clean failed for version $version" -ErrorAction Stop
|
||||
}
|
||||
Write-Output "Building version $version"
|
||||
Invoke-Expression "make PROTOCOL_VERSION=$version"
|
||||
if ($LASTEXITCODE -ne "0") {
|
||||
Write-Error "make failed for version $version" -ErrorAction Stop
|
||||
}
|
||||
Rename-Item -Path "bin/fusion" -newName "$version-fusion"
|
||||
Write-Output "Built version $version"
|
||||
}
|
||||
artifacts:
|
||||
- path: bin
|
||||
name: ubuntu20_04-bin-x64
|
||||
type: zip
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2019
|
||||
build_script:
|
||||
- ps: |
|
||||
$versions = "104", "728"
|
||||
$configurations = "Release", "Debug"
|
||||
|
||||
# AppVeyor uses VS2019 Community
|
||||
$vsPath = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community"
|
||||
|
||||
Import-Module "$vsPath\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
|
||||
Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation
|
||||
|
||||
foreach ($version in $versions) {
|
||||
if (Test-Path -LiteralPath "build") {
|
||||
Remove-Item "build" -Recurse
|
||||
Write-Output "Deleted existing build folder"
|
||||
}
|
||||
Invoke-Expression "cmake -B build -DPROTOCOL_VERSION=$version"
|
||||
if ($LASTEXITCODE -ne "0") {
|
||||
Write-Error "cmake generation failed for version $version" -ErrorAction Stop
|
||||
}
|
||||
Write-Output "Generated build files for version $version"
|
||||
|
||||
foreach ($configuration in $configurations) {
|
||||
Write-Output "Building version $version $configuration"
|
||||
Invoke-Expression "msbuild build\OpenFusion.sln /p:Configuration=$configuration"
|
||||
if ($LASTEXITCODE -ne "0") {
|
||||
Write-Error "msbuild build failed for version $version" -ErrorAction Stop
|
||||
}
|
||||
Rename-Item -Path "bin/$configuration" -newName "$version-$configuration"
|
||||
Write-Output "Built version $version $configuration"
|
||||
}
|
||||
}
|
||||
artifacts:
|
||||
- path: bin
|
||||
name: windows-vs2019-bin-x64
|
||||
type: zip
|
40
config.ini
Normal file
40
config.ini
Normal file
@@ -0,0 +1,40 @@
|
||||
# verbosity level
|
||||
# 0 = mostly silence
|
||||
# 1 = debug prints and unknown packets
|
||||
# 2 = print all packets except LIVE_CHECK and movement
|
||||
# 3 = print all packets
|
||||
verbosity=1
|
||||
|
||||
# Login Server configuration
|
||||
[login]
|
||||
# must be kept in sync with loginInfo.php
|
||||
port=8001
|
||||
# enables two randomly generated characters in the
|
||||
# character selection menu for convenience
|
||||
randomcharacters=true
|
||||
# will all custom names be approved instantly?
|
||||
acceptallcustomnames=true
|
||||
|
||||
# Shard Server configuration
|
||||
[shard]
|
||||
port=8002
|
||||
ip=127.0.0.1
|
||||
# distance at which other players and NPCs become visible
|
||||
playerdistance=20000
|
||||
npcdistance=16000
|
||||
# little message players see when they enter the game
|
||||
motd=Welcome to OpenFusion!
|
||||
# NPC json data
|
||||
npcdata=data/NPCs.json
|
||||
# warp target json data
|
||||
warpdata=data/warps.json
|
||||
# mob json
|
||||
mobdata=data/mobs.json
|
||||
# is everyone a GM?
|
||||
gm=true
|
||||
|
||||
# spawn coordinates (Z is height)
|
||||
# the supplied defaults are at Sector V (future)
|
||||
spawnx=632032
|
||||
spawny=187177
|
||||
spawnz=-5500
|
1
data/NPCs.json
Normal file
1
data/NPCs.json
Normal file
File diff suppressed because one or more lines are too long
1
data/mobs.json
Normal file
1
data/mobs.json
Normal file
File diff suppressed because one or more lines are too long
1
data/warps.json
Normal file
1
data/warps.json
Normal file
File diff suppressed because one or more lines are too long
BIN
res/radiorave_logo.png
Normal file
BIN
res/radiorave_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
@@ -1,13 +1,13 @@
|
||||
#include "CNLoginServer.hpp"
|
||||
#include "CNShared.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "Database.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include <regex>
|
||||
#include "contrib/bcrypt/BCrypt.hpp"
|
||||
|
||||
#include "settings.hpp"
|
||||
|
||||
/*
|
||||
This is *not* connected to any database, so i'm sending dummy data just to get the client to work & connect to the shard <3
|
||||
*/
|
||||
|
||||
std::map<CNSocket*, CNLoginData> CNLoginServer::loginSessions;
|
||||
|
||||
CNLoginServer::CNLoginServer(uint16_t p) {
|
||||
@@ -17,90 +17,133 @@ CNLoginServer::CNLoginServer(uint16_t p) {
|
||||
}
|
||||
|
||||
void CNLoginServer::handlePacket(CNSocket* sock, CNPacketData* data) {
|
||||
printPacket(data, CL2LS);
|
||||
|
||||
switch (data->type) {
|
||||
case P_CL2LS_REQ_LOGIN: {
|
||||
sP_CL2LS_REQ_LOGIN* login = (sP_CL2LS_REQ_LOGIN*)data->buf;
|
||||
sP_LS2CL_REP_LOGIN_SUCC* response = (sP_LS2CL_REP_LOGIN_SUCC*)xmalloc(sizeof(sP_LS2CL_REP_LOGIN_SUCC));
|
||||
uint64_t cachedKey = sock->getEKey(); // so we can still send the response packet with the correct key
|
||||
int charCount = 2; // send 4 randomly generated characters for now
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_LOGIN))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2LS_REQ_LOGIN:" << std::endl;
|
||||
std::cout << "\tClient version: " << login->iClientVerA << "." << login->iClientVerB << "." << login->iClientVerC << std::endl;
|
||||
std::cout << "\tLogin type: " << login->iLoginType << std::endl;
|
||||
std::cout << "\tID: " << U16toU8(login->szID) << " Password: " << U16toU8(login->szPassword) << std::endl;
|
||||
)
|
||||
sP_CL2LS_REQ_LOGIN* login = (sP_CL2LS_REQ_LOGIN*)data->buf;
|
||||
//TODO: implement better way of sending credentials
|
||||
std::string userLogin = U16toU8(login->szID);
|
||||
std::string userPassword = U16toU8(login->szPassword);
|
||||
|
||||
response->iCharCount = charCount;
|
||||
response->iSlotNum = 1;
|
||||
response->iPaymentFlag = 1;
|
||||
response->iOpenBetaFlag = 0;
|
||||
response->uiSvrTime = getTime();
|
||||
bool success = false;
|
||||
int errorCode = 0;
|
||||
|
||||
// set username in response packet
|
||||
memcpy(response->szID, login->szID, sizeof(char16_t) * 33);
|
||||
|
||||
// update keys
|
||||
sock->setEKey(CNSocketEncryption::createNewKey(response->uiSvrTime, response->iCharCount + 1, response->iSlotNum + 1));
|
||||
sock->setFEKey(CNSocketEncryption::createNewKey((uint64_t)(*(uint64_t*)&CNSocketEncryption::defaultKey[0]), login->iClientVerC, 1));
|
||||
|
||||
// send the response in with original key
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_LS2CL_REP_LOGIN_SUCC, sizeof(sP_LS2CL_REP_LOGIN_SUCC), cachedKey));
|
||||
|
||||
loginSessions[sock] = CNLoginData();
|
||||
|
||||
if (settings::LOGINRANDCHARACTERS) {
|
||||
// now send the characters :)
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
sP_LS2CL_REP_CHAR_INFO* charInfo = (sP_LS2CL_REP_CHAR_INFO*)xmalloc(sizeof(sP_LS2CL_REP_CHAR_INFO));
|
||||
charInfo->iSlot = (int8_t)i + 1;
|
||||
charInfo->iLevel = (int16_t)1;
|
||||
charInfo->sPC_Style.iPC_UID = rand(); // unique identifier for the character
|
||||
charInfo->sPC_Style.iNameCheck = 1;
|
||||
charInfo->sPC_Style.iGender = (i%2)+1; // can be 1(boy) or 2(girl)
|
||||
charInfo->sPC_Style.iFaceStyle = 1;
|
||||
charInfo->sPC_Style.iHairStyle = 1;
|
||||
charInfo->sPC_Style.iHairColor = (rand()%19) + 1; // 1 - 19
|
||||
charInfo->sPC_Style.iSkinColor = (rand()%13) + 1; // 1 - 13
|
||||
charInfo->sPC_Style.iEyeColor = (rand()%6) + 1; // 1 - 6
|
||||
charInfo->sPC_Style.iHeight = (rand()%6); // 0 -5
|
||||
charInfo->sPC_Style.iBody = (rand()%4); // 0 - 3
|
||||
charInfo->sPC_Style.iClass = 0;
|
||||
charInfo->sPC_Style2 = sPCStyle2(1, 1, 1);
|
||||
|
||||
// past's town hall
|
||||
charInfo->iX = settings::SPAWN_X;
|
||||
charInfo->iY = settings::SPAWN_Y;
|
||||
charInfo->iZ = settings::SPAWN_Z;
|
||||
|
||||
U8toU16(std::string("Player"), charInfo->sPC_Style.szFirstName);
|
||||
U8toU16(std::to_string(i + 1), charInfo->sPC_Style.szLastName);
|
||||
|
||||
int64_t UID = charInfo->sPC_Style.iPC_UID;
|
||||
loginSessions[sock].characters[UID] = Player();
|
||||
loginSessions[sock].characters[UID].level = charInfo->iLevel;
|
||||
loginSessions[sock].characters[UID].slot = charInfo->iSlot;
|
||||
loginSessions[sock].characters[UID].FEKey = sock->getFEKey();
|
||||
loginSessions[sock].characters[UID].x = charInfo->iX;
|
||||
loginSessions[sock].characters[UID].y = charInfo->iY;
|
||||
loginSessions[sock].characters[UID].z = charInfo->iZ;
|
||||
loginSessions[sock].characters[UID].PCStyle = charInfo->sPC_Style;
|
||||
loginSessions[sock].characters[UID].PCStyle2 = charInfo->sPC_Style2;
|
||||
|
||||
for (int i = 0; i < AEQUIP_COUNT; i++) {
|
||||
// setup item
|
||||
charInfo->aEquip[i].iID = 0;
|
||||
charInfo->aEquip[i].iType = i;
|
||||
charInfo->aEquip[i].iOpt = 0;
|
||||
loginSessions[sock].characters[UID].Equip[i] = charInfo->aEquip[i];
|
||||
//checking regex
|
||||
if (!CNLoginServer::isLoginDataGood(userLogin, userPassword))
|
||||
{
|
||||
errorCode = (int)LOGINERRORID::login_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<Database::Account> findUser = Database::findAccount(userLogin);
|
||||
//if account not found, create it
|
||||
if (findUser == nullptr)
|
||||
{
|
||||
loginSessions[sock] = CNLoginData();
|
||||
loginSessions[sock].userID = Database::addAccount(userLogin, userPassword);
|
||||
loginSessions[sock].slot = 1;
|
||||
success = true;
|
||||
}
|
||||
//if user exists, check if password is correct
|
||||
else if (CNLoginServer::isPasswordCorrect(findUser->Password, userPassword))
|
||||
{
|
||||
//check if account isn't currently in use
|
||||
if (CNLoginServer::isAccountInUse(findUser->AccountID) ||
|
||||
PlayerManager::isAccountInUse(findUser->AccountID))
|
||||
{
|
||||
errorCode = (int)LOGINERRORID::id_already_in_use;
|
||||
}
|
||||
|
||||
//if not, login success
|
||||
else
|
||||
{
|
||||
loginSessions[sock] = CNLoginData();
|
||||
loginSessions[sock].userID = findUser->AccountID;
|
||||
loginSessions[sock].slot = findUser->Selected;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCode = (int)LOGINERRORID::id_and_password_do_not_match;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (success)
|
||||
{
|
||||
std::vector<Player> characters = Database::getCharacters(loginSessions[sock].userID);
|
||||
int charCount = characters.size();
|
||||
|
||||
INITSTRUCT(sP_LS2CL_REP_LOGIN_SUCC, resp);
|
||||
// set username in resp packet
|
||||
memcpy(resp.szID, login->szID, sizeof(char16_t) * 33);
|
||||
|
||||
resp.iCharCount = charCount;
|
||||
resp.iSlotNum = loginSessions[sock].slot;
|
||||
resp.iPaymentFlag = 1;
|
||||
resp.iOpenBetaFlag = 0;
|
||||
resp.uiSvrTime = getTime();
|
||||
|
||||
// send the resp in with original key
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_LOGIN_SUCC, sizeof(sP_LS2CL_REP_LOGIN_SUCC));
|
||||
|
||||
// update keys
|
||||
sock->setEKey(CNSocketEncryption::createNewKey(resp.uiSvrTime, resp.iCharCount + 1, resp.iSlotNum + 1));
|
||||
sock->setFEKey(CNSocketEncryption::createNewKey((uint64_t)(*(uint64_t*)&CNSocketEncryption::defaultKey[0]), login->iClientVerC, 1));
|
||||
|
||||
// now send the characters :)
|
||||
std::vector<Player>::iterator it;
|
||||
for (it = characters.begin(); it != characters.end(); it++)
|
||||
{
|
||||
sP_LS2CL_REP_CHAR_INFO charInfo = sP_LS2CL_REP_CHAR_INFO();
|
||||
|
||||
charInfo.iSlot = (int8_t)it->slot;
|
||||
charInfo.iLevel = (int16_t)it->level;
|
||||
charInfo.sPC_Style = it->PCStyle;
|
||||
charInfo.sPC_Style2 = it->PCStyle2;
|
||||
|
||||
// position
|
||||
charInfo.iX = it->x;
|
||||
charInfo.iY = it->y;
|
||||
charInfo.iZ = it->z;
|
||||
|
||||
//save character in session (for char select)
|
||||
int UID = it->iID;
|
||||
loginSessions[sock].characters[UID] = Player(*it);
|
||||
loginSessions[sock].characters[UID].FEKey = sock->getFEKey();
|
||||
|
||||
//temporary inventory stuff
|
||||
for (int i = 0; i < 4; i++) {
|
||||
//equip char creation clothes and lightning rifle
|
||||
charInfo.aEquip[i] = it->Equip[i];
|
||||
}
|
||||
|
||||
for (int i = 5; i < AEQUIP_COUNT; i++) {
|
||||
// empty equips
|
||||
charInfo.aEquip[i].iID = 0;
|
||||
charInfo.aEquip[i].iType = i;
|
||||
charInfo.aEquip[i].iOpt = 0;
|
||||
}
|
||||
|
||||
// set default to the first character
|
||||
if (i == 0)
|
||||
if (it == characters.begin())
|
||||
loginSessions[sock].selectedChar = UID;
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)charInfo, P_LS2CL_REP_CHAR_INFO, sizeof(sP_LS2CL_REP_CHAR_INFO), sock->getEKey()));
|
||||
sock->sendPacket((void*)&charInfo, P_LS2CL_REP_CHAR_INFO, sizeof(sP_LS2CL_REP_CHAR_INFO));
|
||||
}
|
||||
}
|
||||
//Failure
|
||||
else {
|
||||
INITSTRUCT(sP_LS2CL_REP_LOGIN_FAIL, resp);
|
||||
|
||||
memcpy(resp.szID, login->szID, sizeof(char16_t) * 33);
|
||||
resp.iErrorCode = errorCode;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_LOGIN_FAIL, sizeof(sP_LS2CL_REP_LOGIN_FAIL));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -110,44 +153,67 @@ void CNLoginServer::handlePacket(CNSocket* sock, CNPacketData* data) {
|
||||
break;
|
||||
}
|
||||
case P_CL2LS_REQ_CHECK_CHAR_NAME: {
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_CHECK_CHAR_NAME))
|
||||
return;
|
||||
|
||||
// naughty words allowed!!!!!!!! (also for some reason, the client will always show 'Player 0' if you manually type a name. It will show up for other connected players though)
|
||||
sP_CL2LS_REQ_CHECK_CHAR_NAME* nameCheck = (sP_CL2LS_REQ_CHECK_CHAR_NAME*)data->buf;
|
||||
sP_LS2CL_REP_CHECK_CHAR_NAME_SUCC* response = (sP_LS2CL_REP_CHECK_CHAR_NAME_SUCC*)xmalloc(sizeof(sP_LS2CL_REP_CHECK_CHAR_NAME_SUCC));
|
||||
//check if name is occupied
|
||||
if (Database::isNameFree(nameCheck))
|
||||
{
|
||||
// naughty words allowed!!!!!!!! (also for some reason, the client will always show 'Player + ID' if you manually type a name. It will show up for other connected players though)
|
||||
|
||||
DEBUGLOG(
|
||||
INITSTRUCT(sP_LS2CL_REP_CHECK_CHAR_NAME_SUCC, resp);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2LS_REQ_CHECK_CHAR_NAME:" << std::endl;
|
||||
std::cout << "\tFirstName: " << U16toU8(nameCheck->szFirstName) << " LastName: " << U16toU8(nameCheck->szLastName) << std::endl;
|
||||
)
|
||||
)
|
||||
|
||||
memcpy(response->szFirstName, nameCheck->szFirstName, sizeof(char16_t) * 9);
|
||||
memcpy(response->szLastName, nameCheck->szLastName, sizeof(char16_t) * 17);
|
||||
|
||||
// fr*ck allowed!!!
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_LS2CL_REP_CHECK_CHAR_NAME_SUCC, sizeof(sP_LS2CL_REP_CHECK_CHAR_NAME_SUCC), sock->getEKey()));
|
||||
memcpy(resp.szFirstName, nameCheck->szFirstName, sizeof(char16_t) * 9);
|
||||
memcpy(resp.szLastName, nameCheck->szLastName, sizeof(char16_t) * 17);
|
||||
|
||||
// fr*ck allowed!!!
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_CHECK_CHAR_NAME_SUCC, sizeof(sP_LS2CL_REP_CHECK_CHAR_NAME_SUCC));
|
||||
}
|
||||
else {
|
||||
INITSTRUCT(sP_LS2CL_REP_CHECK_CHAR_NAME_FAIL, resp);
|
||||
resp.iErrorCode = 1;
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_CHECK_CHAR_NAME_FAIL, sizeof(sP_LS2CL_REP_CHECK_CHAR_NAME_FAIL));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case P_CL2LS_REQ_SAVE_CHAR_NAME: {
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_SAVE_CHAR_NAME))
|
||||
return;
|
||||
|
||||
sP_CL2LS_REQ_SAVE_CHAR_NAME* save = (sP_CL2LS_REQ_SAVE_CHAR_NAME*)data->buf;
|
||||
sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC* response = (sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC*)xmalloc(sizeof(sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC));
|
||||
|
||||
INITSTRUCT(sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC, resp);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2LS_REQ_SAVE_CHAR_NAME:" << std::endl;
|
||||
std::cout << "\tSlot: " << (int)save->iSlotNum << std::endl;
|
||||
std::cout << "\tGender: " << (int)save->iGender << std::endl;
|
||||
std::cout << "\tName: " << U16toU8(save->szFirstName) << " " << U16toU8(save->szLastName) << std::endl;
|
||||
)
|
||||
|
||||
response->iSlotNum = save->iSlotNum;
|
||||
response->iGender = save->iGender;
|
||||
memcpy(response->szFirstName, save->szFirstName, sizeof(char16_t) * 9);
|
||||
memcpy(response->szLastName, save->szLastName, sizeof(char16_t) * 17);
|
||||
resp.iSlotNum = save->iSlotNum;
|
||||
resp.iGender = save->iGender;
|
||||
resp.iPC_UID = Database::createCharacter(save, loginSessions[sock].userID);
|
||||
memcpy(resp.szFirstName, save->szFirstName, sizeof(char16_t) * 9);
|
||||
memcpy(resp.szLastName, save->szLastName, sizeof(char16_t) * 17);
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_LS2CL_REP_SAVE_CHAR_NAME_SUCC, sizeof(sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC), sock->getEKey()));
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_SAVE_CHAR_NAME_SUCC, sizeof(sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC));
|
||||
|
||||
Database::updateSelected(loginSessions[sock].userID, save->iSlotNum);
|
||||
break;
|
||||
}
|
||||
case P_CL2LS_REQ_CHAR_CREATE: {
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_CHAR_CREATE))
|
||||
return;
|
||||
|
||||
sP_CL2LS_REQ_CHAR_CREATE* character = (sP_CL2LS_REQ_CHAR_CREATE*)data->buf;
|
||||
sP_LS2CL_REP_CHAR_CREATE_SUCC* response = (sP_LS2CL_REP_CHAR_CREATE_SUCC*)xmalloc(sizeof(sP_LS2CL_REP_CHAR_CREATE_SUCC));
|
||||
Database::finishCharacter(character);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2LS_REQ_CHAR_CREATE:" << std::endl;
|
||||
@@ -167,36 +233,47 @@ void CNLoginServer::handlePacket(CNSocket* sock, CNPacketData* data) {
|
||||
std::cout << "\tiEquipLBID: " << (int)character->sOn_Item.iEquipLBID << std::endl;
|
||||
std::cout << "\tiEquipFootID: " << (int)character->sOn_Item.iEquipFootID << std::endl;
|
||||
)
|
||||
|
||||
Player player =
|
||||
Database::DbToPlayer(
|
||||
Database::getDbPlayerById(character->PCStyle.iPC_UID)
|
||||
);
|
||||
int64_t UID = player.iID;
|
||||
|
||||
character->PCStyle.iNameCheck = 1;
|
||||
response->PC_Style = character->PCStyle;
|
||||
response->PC_Style2 = sPCStyle2(1, 1, 1);
|
||||
response->iLevel = 1;
|
||||
response->sOn_Item = character->sOn_Item;
|
||||
INITSTRUCT(sP_LS2CL_REP_CHAR_CREATE_SUCC, resp);
|
||||
resp.sPC_Style = player.PCStyle;
|
||||
resp.sPC_Style2 = player.PCStyle2;
|
||||
resp.iLevel = player.level;
|
||||
resp.sOn_Item = character->sOn_Item;
|
||||
|
||||
int64_t UID = character->PCStyle.iPC_UID;
|
||||
loginSessions[sock].characters[UID] = Player();
|
||||
loginSessions[sock].characters[UID].level = 1;
|
||||
//save player in session
|
||||
loginSessions[sock].characters[UID] = Player(player);
|
||||
loginSessions[sock].characters[UID].FEKey = sock->getFEKey();
|
||||
loginSessions[sock].characters[UID].PCStyle = character->PCStyle;
|
||||
loginSessions[sock].characters[UID].PCStyle2 = sPCStyle2(1, 0, 1);
|
||||
loginSessions[sock].characters[UID].x = settings::SPAWN_X;
|
||||
loginSessions[sock].characters[UID].y = settings::SPAWN_Y;
|
||||
loginSessions[sock].characters[UID].z = settings::SPAWN_Z;
|
||||
loginSessions[sock].characters[UID].Equip[1].iID = character->sOn_Item.iEquipUBID; // upper body
|
||||
loginSessions[sock].characters[UID].Equip[1].iType = 1;
|
||||
loginSessions[sock].characters[UID].Equip[2].iID = character->sOn_Item.iEquipLBID; // lower body
|
||||
loginSessions[sock].characters[UID].Equip[2].iType = 2;
|
||||
loginSessions[sock].characters[UID].Equip[3].iID = character->sOn_Item.iEquipFootID; // foot!
|
||||
loginSessions[sock].characters[UID].Equip[3].iType = 3;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_CHAR_CREATE_SUCC, sizeof(sP_LS2CL_REP_CHAR_CREATE_SUCC));
|
||||
Database::updateSelected(loginSessions[sock].userID, player.slot);
|
||||
break;
|
||||
}
|
||||
case P_CL2LS_REQ_CHAR_DELETE: {
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_CHAR_DELETE))
|
||||
return;
|
||||
|
||||
sP_CL2LS_REQ_CHAR_DELETE* del = (sP_CL2LS_REQ_CHAR_DELETE*)data->buf;
|
||||
int operationResult = Database::deleteCharacter(del->iPC_UID);
|
||||
|
||||
INITSTRUCT(sP_LS2CL_REP_CHAR_DELETE_SUCC, resp);
|
||||
resp.iSlotNum = operationResult;
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_CHAR_DELETE_SUCC, sizeof(sP_LS2CL_REP_CHAR_DELETE_SUCC));
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_LS2CL_REP_CHAR_CREATE_SUCC, sizeof(sP_LS2CL_REP_CHAR_CREATE_SUCC), sock->getEKey()));
|
||||
break;
|
||||
}
|
||||
case P_CL2LS_REQ_CHAR_SELECT: {
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_CHAR_SELECT))
|
||||
return;
|
||||
|
||||
// character selected
|
||||
sP_CL2LS_REQ_CHAR_SELECT* chararacter = (sP_CL2LS_REQ_CHAR_SELECT*)data->buf;
|
||||
sP_LS2CL_REP_CHAR_SELECT_SUCC* response = (sP_LS2CL_REP_CHAR_SELECT_SUCC*)xmalloc(sizeof(sP_LS2CL_REP_CHAR_SELECT_SUCC));
|
||||
INITSTRUCT(sP_LS2CL_REP_CHAR_SELECT_SUCC, resp);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2LS_REQ_CHAR_SELECT:" << std::endl;
|
||||
@@ -204,41 +281,132 @@ void CNLoginServer::handlePacket(CNSocket* sock, CNPacketData* data) {
|
||||
)
|
||||
|
||||
loginSessions[sock].selectedChar = chararacter->iPC_UID;
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_LS2CL_REP_CHAR_SELECT_SUCC, sizeof(sP_LS2CL_REP_CHAR_SELECT_SUCC), sock->getEKey()));
|
||||
Database::updateSelected(loginSessions[sock].userID, loginSessions[sock].characters[chararacter->iPC_UID].slot);
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_CHAR_SELECT_SUCC, sizeof(sP_LS2CL_REP_CHAR_SELECT_SUCC));
|
||||
break;
|
||||
}
|
||||
case P_CL2LS_REQ_SHARD_SELECT: {
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_SHARD_SELECT))
|
||||
return;
|
||||
|
||||
// tell client to connect to the shard server
|
||||
sP_CL2LS_REQ_SHARD_SELECT* shard = (sP_CL2LS_REQ_SHARD_SELECT*)data->buf;
|
||||
sP_LS2CL_REP_SHARD_SELECT_SUCC* response = (sP_LS2CL_REP_SHARD_SELECT_SUCC*)xmalloc(sizeof(sP_LS2CL_REP_SHARD_SELECT_SUCC));
|
||||
INITSTRUCT(sP_LS2CL_REP_SHARD_SELECT_SUCC, resp);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2LS_REQ_SHARD_SELECT:" << std::endl;
|
||||
std::cout << "\tShard: " << (int)shard->iShardNum << std::endl;
|
||||
std::cout << "\tShard: " << (int)shard->ShardNum << std::endl;
|
||||
)
|
||||
|
||||
const char* SHARD_IP = settings::SHARDSERVERIP.c_str();
|
||||
response->iEnterSerialKey = rand();
|
||||
response->g_FE_ServerPort = settings::SHARDPORT;
|
||||
resp.iEnterSerialKey = rand();
|
||||
resp.g_FE_ServerPort = settings::SHARDPORT;
|
||||
|
||||
// copy IP to response (this struct uses ASCII encoding so we don't have to goof around converting encodings)
|
||||
memcpy(response->g_FE_ServerIP, SHARD_IP, strlen(SHARD_IP));
|
||||
response->g_FE_ServerIP[strlen(SHARD_IP)] = '\0';
|
||||
// copy IP to resp (this struct uses ASCII encoding so we don't have to goof around converting encodings)
|
||||
memcpy(resp.g_FE_ServerIP, SHARD_IP, strlen(SHARD_IP));
|
||||
resp.g_FE_ServerIP[strlen(SHARD_IP)] = '\0';
|
||||
|
||||
// pass player to CNSharedData
|
||||
CNSharedData::setPlayer(response->iEnterSerialKey, loginSessions[sock].characters[loginSessions[sock].selectedChar]);
|
||||
CNSharedData::setPlayer(resp.iEnterSerialKey, loginSessions[sock].characters[loginSessions[sock].selectedChar]);
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_LS2CL_REP_SHARD_SELECT_SUCC, sizeof(sP_LS2CL_REP_SHARD_SELECT_SUCC), sock->getEKey()));
|
||||
sock->kill(); // client should connect to the Shard server now
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_SHARD_SELECT_SUCC, sizeof(sP_LS2CL_REP_SHARD_SELECT_SUCC));
|
||||
break;
|
||||
}
|
||||
case P_CL2LS_REQ_SAVE_CHAR_TUTOR: {
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_SAVE_CHAR_TUTOR))
|
||||
return;
|
||||
sP_CL2LS_REQ_SAVE_CHAR_TUTOR* save = (sP_CL2LS_REQ_SAVE_CHAR_TUTOR*)data->buf;
|
||||
Database::finishTutorial(save->iPC_UID);
|
||||
loginSessions[sock].characters[save->iPC_UID].PCStyle2.iTutorialFlag = 1;
|
||||
loginSessions[sock].characters[save->iPC_UID].Equip[0].iID = 328;
|
||||
loginSessions[sock].characters[save->iPC_UID].Equip[0].iType = 0;
|
||||
loginSessions[sock].characters[save->iPC_UID].Equip[0].iOpt = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
case P_CL2LS_REQ_CHANGE_CHAR_NAME: {
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_CHANGE_CHAR_NAME))
|
||||
return;
|
||||
sP_CL2LS_REQ_CHANGE_CHAR_NAME* save = (sP_CL2LS_REQ_CHANGE_CHAR_NAME*)data->buf;
|
||||
Database::changeName(save);
|
||||
INITSTRUCT(sP_LS2CL_REP_CHANGE_CHAR_NAME_SUCC, resp);
|
||||
resp.iPC_UID = save->iPCUID;
|
||||
memcpy(resp.szFirstName, save->szFirstName, sizeof(char16_t)*9);
|
||||
memcpy(resp.szLastName, save->szLastName, sizeof(char16_t) * 17);
|
||||
resp.iSlotNum = save->iSlotNum;
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_CHANGE_CHAR_NAME_SUCC, sizeof(sP_LS2CL_REP_CHANGE_CHAR_NAME_SUCC));
|
||||
break;
|
||||
}
|
||||
case P_CL2LS_REQ_PC_EXIT_DUPLICATE:{
|
||||
if (data->size != sizeof(sP_CL2LS_REQ_PC_EXIT_DUPLICATE))
|
||||
return;
|
||||
|
||||
sP_CL2LS_REQ_PC_EXIT_DUPLICATE* exit = (sP_CL2LS_REQ_PC_EXIT_DUPLICATE*)data->buf;
|
||||
auto account = Database::findAccount(U16toU8(exit->szID));
|
||||
if (account == nullptr)
|
||||
break;
|
||||
|
||||
int accountId = account->AccountID;
|
||||
if (!exitDuplicate(accountId))
|
||||
PlayerManager::exitDuplicate(accountId);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
std::cerr << "OpenFusion: LOGIN UNIMPLM ERR. PacketType: " << data->type << std::endl;
|
||||
if (settings::VERBOSITY)
|
||||
std::cerr << "OpenFusion: LOGIN UNIMPLM ERR. PacketType: " << Defines::p2str(CL2LS, data->type) << " (" << data->type << ")" << std::endl;
|
||||
break;
|
||||
/* Unimplemented CL2LS packets:
|
||||
P_CL2LS_CHECK_NAME_LIST - unused by the client
|
||||
P_CL2LS_REQ_SERVER_SELECT
|
||||
P_CL2LS_REQ_SHARD_LIST_INFO - dev commands, useless as we only run 1 server
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void CNLoginServer::newConnection(CNSocket* cns) {
|
||||
cns->setActiveKey(SOCKETKEY_E); // by default they accept keys encrypted with the default key
|
||||
}
|
||||
|
||||
void CNLoginServer::killConnection(CNSocket* cns) {
|
||||
loginSessions.erase(cns);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region helperMethods
|
||||
bool CNLoginServer::isAccountInUse(int accountId) {
|
||||
std::map<CNSocket*, CNLoginData>::iterator it;
|
||||
for (it = CNLoginServer::loginSessions.begin(); it != CNLoginServer::loginSessions.end(); it++)
|
||||
{
|
||||
if (it->second.userID == accountId)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool CNLoginServer::exitDuplicate(int accountId)
|
||||
{
|
||||
std::map<CNSocket*, CNLoginData>::iterator it;
|
||||
for (it = CNLoginServer::loginSessions.begin(); it != CNLoginServer::loginSessions.end(); it++)
|
||||
{
|
||||
if (it->second.userID == accountId)
|
||||
{
|
||||
CNSocket* sock = it->first;
|
||||
INITSTRUCT(sP_LS2CL_REP_PC_EXIT_DUPLICATE, resp);
|
||||
resp.iErrorCode = 0;
|
||||
sock->sendPacket((void*)&resp, P_LS2CL_REP_PC_EXIT_DUPLICATE, sizeof(sP_LS2CL_REP_PC_EXIT_DUPLICATE));
|
||||
sock->kill();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool CNLoginServer::isLoginDataGood(std::string login, std::string password)
|
||||
{
|
||||
std::regex loginRegex("[a-zA-Z0-9_-]{4,32}");
|
||||
std::regex passwordRegex("[a-zA-Z0-9!@#$%^&*()_+]{8,32}");
|
||||
return (std::regex_match(login, loginRegex) && std::regex_match(password, passwordRegex));
|
||||
}
|
||||
bool CNLoginServer::isPasswordCorrect(std::string actualPassword, std::string tryPassword)
|
||||
{
|
||||
return BCrypt::validatePassword(tryPassword, actualPassword);
|
||||
}
|
||||
#pragma endregion helperMethods
|
||||
|
@@ -1,37 +1,27 @@
|
||||
#ifndef _CNLS_HPP
|
||||
#define _CNLS_HPP
|
||||
#pragma once
|
||||
|
||||
#include "CNProtocol.hpp"
|
||||
#include "Defines.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
enum LOGINPACKETID {
|
||||
// client to login server
|
||||
P_CL2LS_REQ_LOGIN = 301989889,
|
||||
P_CL2LS_REQ_CHECK_CHAR_NAME = 301989890,
|
||||
P_CL2LS_REQ_SAVE_CHAR_NAME = 301989891,
|
||||
P_CL2LS_REQ_CHAR_CREATE = 301989892,
|
||||
P_CL2LS_REQ_CHAR_SELECT = 301989893,
|
||||
P_CL2LS_REQ_SHARD_SELECT = 301989895,
|
||||
P_CL2LS_REP_LIVE_CHECK = 301989900,
|
||||
P_CL2LS_REQ_SHARD_LIST_INFO = 301989896,
|
||||
|
||||
// login server 2 client
|
||||
P_LS2CL_REP_LOGIN_SUCC = 553648129,
|
||||
P_LS2CL_REP_CHAR_INFO = 553648131,
|
||||
P_LS2CL_REP_CHECK_CHAR_NAME_SUCC = 553648133,
|
||||
P_LS2CL_REP_SAVE_CHAR_NAME_SUCC = 553648135,
|
||||
P_LS2CL_REP_CHAR_CREATE_SUCC = 553648137,
|
||||
P_LS2CL_REP_CHAR_SELECT_SUCC = 553648139,
|
||||
P_LS2CL_REP_SHARD_SELECT_SUCC = 553648143,
|
||||
P_LS2CL_REQ_LIVE_CHECK = 553648150,
|
||||
P_LS2CL_REP_SHARD_LIST_INFO_SUCC = 553648153
|
||||
};
|
||||
|
||||
struct CNLoginData {
|
||||
std::map<int64_t, Player> characters;
|
||||
int64_t selectedChar;
|
||||
int userID; int slot;
|
||||
};
|
||||
|
||||
enum class LOGINERRORID {
|
||||
database_error = 0,
|
||||
id_doesnt_exist = 1,
|
||||
id_and_password_do_not_match = 2,
|
||||
id_already_in_use = 3,
|
||||
login_error = 4,
|
||||
client_version_outdated = 6,
|
||||
you_are_not_an_authorized_beta_tester = 7,
|
||||
authentication_connection_error = 8,
|
||||
updated_euala_required = 9
|
||||
};
|
||||
|
||||
// WARNING: THERE CAN ONLY BE ONE OF THESE SERVERS AT A TIME!!!!!! TODO: change loginSessions & packet handlers to be non-static
|
||||
@@ -39,11 +29,15 @@ class CNLoginServer : public CNServer {
|
||||
private:
|
||||
static void handlePacket(CNSocket* sock, CNPacketData* data);
|
||||
static std::map<CNSocket*, CNLoginData> loginSessions;
|
||||
|
||||
|
||||
static bool isLoginDataGood(std::string login, std::string password);
|
||||
static bool isPasswordCorrect(std::string actualPassword, std::string tryPassword);
|
||||
static bool isAccountInUse(int accountId);
|
||||
//returns true if success
|
||||
static bool exitDuplicate(int accountId);
|
||||
public:
|
||||
CNLoginServer(uint16_t p);
|
||||
|
||||
void killConnection(CNSocket* cns);
|
||||
void newConnection(CNSocket* cns);
|
||||
void killConnection(CNSocket* cns);
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,4 +1,5 @@
|
||||
#include "CNProtocol.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
|
||||
// ========================================================[[ CNSocketEncryption ]]========================================================
|
||||
|
||||
@@ -58,11 +59,7 @@ int CNSocketEncryption::decryptData(uint8_t* buffer, uint8_t* key, int size) {
|
||||
|
||||
// ========================================================[[ CNPacketData ]]========================================================
|
||||
|
||||
CNPacketData::CNPacketData(void* b, uint32_t t, int l, uint64_t k): buf(b), type(t), size(l), key(k) {}
|
||||
|
||||
CNPacketData::~CNPacketData() {
|
||||
free(buf); // we own the buffer
|
||||
}
|
||||
CNPacketData::CNPacketData(void* b, uint32_t t, int l): buf(b), size(l), type(t) {}
|
||||
|
||||
// ========================================================[[ CNSocket ]]========================================================
|
||||
|
||||
@@ -72,11 +69,18 @@ CNSocket::CNSocket(SOCKET s, PacketHandler ph): sock(s), pHandler(ph) {
|
||||
|
||||
bool CNSocket::sendData(uint8_t* data, int size) {
|
||||
int sentBytes = 0;
|
||||
int maxTries = 10;
|
||||
|
||||
while (sentBytes < size) {
|
||||
int sent = send(sock, (buffer_t*)(data + sentBytes), size - sentBytes, 0); // no flags defined
|
||||
if (SOCKETERROR(sent))
|
||||
if (SOCKETERROR(sent)) {
|
||||
if (OF_ERRNO == OF_EWOULD && maxTries > 0) {
|
||||
maxTries--;
|
||||
continue; // try again
|
||||
}
|
||||
std::cout << "[FATAL] SOCKET ERROR: " << OF_ERRNO << std::endl;
|
||||
return false; // error occured while sending bytes
|
||||
}
|
||||
sentBytes += sent;
|
||||
}
|
||||
|
||||
@@ -114,28 +118,51 @@ void CNSocket::kill() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void CNSocket::sendPacket(CNPacketData* pak) {
|
||||
int tmpSize = pak->size + sizeof(uint32_t);
|
||||
uint8_t* tmpBuf = (uint8_t*)xmalloc(tmpSize);
|
||||
// we don't own buf, TODO: queue packets up to send in step()
|
||||
void CNSocket::sendPacket(void* buf, uint32_t type, size_t size) {
|
||||
if (!alive)
|
||||
return;
|
||||
|
||||
size_t bodysize = size + sizeof(uint32_t);
|
||||
uint8_t* fullpkt = (uint8_t*)xmalloc(bodysize+4);
|
||||
uint8_t* body = fullpkt+4;
|
||||
memcpy(fullpkt, (void*)&bodysize, 4);
|
||||
|
||||
// copy packet type to the front of the buffer & then the actual buffer
|
||||
memcpy(tmpBuf, (void*)&pak->type, sizeof(uint32_t));
|
||||
memcpy(tmpBuf+sizeof(uint32_t), pak->buf, pak->size);
|
||||
memcpy(body, (void*)&type, sizeof(uint32_t));
|
||||
memcpy(body+sizeof(uint32_t), buf, size);
|
||||
|
||||
// encrypt the packet
|
||||
CNSocketEncryption::encryptData((uint8_t*)tmpBuf, (uint8_t*)(&pak->key), tmpSize);
|
||||
|
||||
// send packet size
|
||||
sendData((uint8_t*)&tmpSize, sizeof(uint32_t));
|
||||
switch (activeKey) {
|
||||
case SOCKETKEY_E:
|
||||
CNSocketEncryption::encryptData((uint8_t*)body, (uint8_t*)(&EKey), bodysize);
|
||||
break;
|
||||
case SOCKETKEY_FE:
|
||||
CNSocketEncryption::encryptData((uint8_t*)body, (uint8_t*)(&FEKey), bodysize);
|
||||
break;
|
||||
default: {
|
||||
free(fullpkt);
|
||||
DEBUGLOG(
|
||||
std::cout << "[WARN]: UNSET KEYTYPE FOR SOCKET!! ABORTING SEND" << std::endl;
|
||||
)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// send packet data!
|
||||
sendData(tmpBuf, tmpSize);
|
||||
if (alive && !sendData(fullpkt, bodysize+4))
|
||||
kill();
|
||||
|
||||
delete pak;
|
||||
free(tmpBuf); // free tmp buffer
|
||||
free(fullpkt);
|
||||
}
|
||||
|
||||
void CNSocket::setActiveKey(ACTIVEKEY key) {
|
||||
activeKey = key;
|
||||
}
|
||||
|
||||
void CNSocket::step() {
|
||||
// read step
|
||||
|
||||
if (readSize <= 0) {
|
||||
// we aren't reading a packet yet, try to start looking for one
|
||||
int recved = recv(sock, (buffer_t*)readBuffer, sizeof(int32_t), 0);
|
||||
@@ -143,13 +170,17 @@ void CNSocket::step() {
|
||||
// we got out packet size!!!!
|
||||
readSize = *((int32_t*)readBuffer);
|
||||
// sanity check
|
||||
if (readSize > MAX_PACKETSIZE) {
|
||||
if (readSize > CN_PACKET_BUFFER_SIZE) {
|
||||
kill();
|
||||
return;
|
||||
}
|
||||
|
||||
// we'll just leave bufferIndex at 0 since we already have the packet size, it's safe to overwrite those bytes
|
||||
activelyReading = true;
|
||||
} else if (OF_ERRNO != OF_EWOULD) {
|
||||
// serious socket issue, disconnect connection
|
||||
kill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,19 +189,22 @@ void CNSocket::step() {
|
||||
int recved = recv(sock, (buffer_t*)(readBuffer + readBufferIndex), readSize - readBufferIndex, 0);
|
||||
if (!SOCKETERROR(recved))
|
||||
readBufferIndex += recved;
|
||||
else if (OF_ERRNO != OF_EWOULD) {
|
||||
// serious socket issue, disconnect connection
|
||||
kill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (activelyReading && readBufferIndex - readSize <= 0) {
|
||||
// decrypt readBuffer and copy to CNPacketData
|
||||
CNSocketEncryption::decryptData(readBuffer, (uint8_t*)(&EKey), readSize);
|
||||
CNSocketEncryption::decryptData((uint8_t*)&readBuffer, (uint8_t*)(&EKey), readSize);
|
||||
|
||||
// this doesn't leak memory because we free it in CNPacketData's deconstructor LOL
|
||||
void* tmpBuf = xmalloc(readSize-sizeof(int32_t));
|
||||
memcpy(tmpBuf, readBuffer+sizeof(uint32_t), readSize-sizeof(int32_t));
|
||||
CNPacketData tmp(tmpBuf, *((uint32_t*)readBuffer), readSize-sizeof(int32_t), EKey);
|
||||
void* tmpBuf = readBuffer+sizeof(uint32_t);
|
||||
CNPacketData tmp(tmpBuf, *((uint32_t*)readBuffer), readSize-sizeof(int32_t));
|
||||
|
||||
// CALL PACKET HANDLER!!
|
||||
pHandler(this, &tmp); // tmp's deconstructor will be called when readStep returns so that tmpBuffer we made will be cleaned up :)
|
||||
// call packet handler!!
|
||||
pHandler(this, &tmp);
|
||||
|
||||
// reset vars :)
|
||||
readSize = 0;
|
||||
@@ -234,26 +268,36 @@ CNServer::CNServer(uint16_t p): port(p) {}
|
||||
void CNServer::start() {
|
||||
std::cout << "Starting server at *:" << port << std::endl;
|
||||
// listen to new connections, add to connection list
|
||||
while (true) {
|
||||
while (active) {
|
||||
std::lock_guard<std::mutex> lock(activeCrit);
|
||||
|
||||
// listen for a new connection
|
||||
SOCKET newConnection = accept(sock, (struct sockaddr *)&(address), (socklen_t*)&(addressSize));
|
||||
if (!SOCKETINVALID(newConnection)) {
|
||||
SOCKET newConnectionSocket = accept(sock, (struct sockaddr *)&(address), (socklen_t*)&(addressSize));
|
||||
if (!SOCKETINVALID(newConnectionSocket)) {
|
||||
// new connection! make sure to set non-blocking!
|
||||
#ifdef _WIN32
|
||||
unsigned long mode = 1;
|
||||
if (ioctlsocket(newConnection, FIONBIO, &mode) != 0) {
|
||||
if (ioctlsocket(newConnectionSocket, FIONBIO, &mode) != 0) {
|
||||
#else
|
||||
if (fcntl(newConnection, F_SETFL, (fcntl(sock, F_GETFL, 0) | O_NONBLOCK)) != 0) {
|
||||
if (fcntl(newConnectionSocket, F_SETFL, (fcntl(sock, F_GETFL, 0) | O_NONBLOCK)) != 0) {
|
||||
#endif
|
||||
std::cerr << "[FATAL] OpenFusion: fcntl failed on new connection" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
std::cerr << "[WARN] OpenFusion: fcntl failed on new connection" << std::endl;
|
||||
#ifdef _WIN32
|
||||
shutdown(newConnectionSocket, SD_BOTH);
|
||||
closesocket(newConnectionSocket);
|
||||
#else
|
||||
shutdown(newConnectionSocket, SHUT_RDWR);
|
||||
close(newConnectionSocket);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << "New connection! " << inet_ntoa(address.sin_addr) << std::endl;
|
||||
|
||||
// add connection to list!
|
||||
CNSocket* tmp = new CNSocket(newConnection, pHandler);
|
||||
CNSocket* tmp = new CNSocket(newConnectionSocket, pHandler);
|
||||
connections.push_back(tmp);
|
||||
newConnection(tmp);
|
||||
}
|
||||
|
||||
// for each connection, check if it's alive, if not kill it!
|
||||
@@ -272,6 +316,8 @@ void CNServer::start() {
|
||||
}
|
||||
}
|
||||
|
||||
onStep();
|
||||
|
||||
#ifdef _WIN32
|
||||
Sleep(0);
|
||||
#else
|
||||
@@ -280,4 +326,48 @@ void CNServer::start() {
|
||||
}
|
||||
}
|
||||
|
||||
void CNServer::killConnection(CNSocket* cns) {} // stubbed lol
|
||||
void CNServer::kill() {
|
||||
std::lock_guard<std::mutex> lock(activeCrit); // the lock will be removed when the function ends
|
||||
active = false;
|
||||
|
||||
// kill all connections
|
||||
std::list<CNSocket*>::iterator i = connections.begin();
|
||||
while (i != connections.end()) {
|
||||
CNSocket* cSock = *i;
|
||||
|
||||
if (cSock->isAlive()) {
|
||||
cSock->kill();
|
||||
}
|
||||
|
||||
++i; // go to the next element
|
||||
delete cSock;
|
||||
}
|
||||
|
||||
connections.clear();
|
||||
}
|
||||
|
||||
void CNServer::printPacket(CNPacketData *data, int type) {
|
||||
if (settings::VERBOSITY < 2)
|
||||
return;
|
||||
|
||||
if (settings::VERBOSITY < 3) switch (data->type) {
|
||||
case P_CL2LS_REP_LIVE_CHECK:
|
||||
case P_CL2FE_REP_LIVE_CHECK:
|
||||
case P_CL2FE_REQ_PC_MOVE:
|
||||
case P_CL2FE_REQ_PC_JUMP:
|
||||
case P_CL2FE_REQ_PC_SLOPE:
|
||||
case P_CL2FE_REQ_PC_MOVEPLATFORM:
|
||||
case P_CL2FE_REQ_PC_MOVETRANSPORTATION:
|
||||
case P_CL2FE_REQ_PC_ZIPLINE:
|
||||
case P_CL2FE_REQ_PC_JUMPPAD:
|
||||
case P_CL2FE_REQ_PC_LAUNCHER:
|
||||
case P_CL2FE_REQ_PC_STOP:
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "OpenFusion: received " << Defines::p2str(type, data->type) << " (" << data->type << ")" << std::endl;
|
||||
}
|
||||
|
||||
void CNServer::newConnection(CNSocket* cns) {} // stubbed
|
||||
void CNServer::killConnection(CNSocket* cns) {} // stubbed
|
||||
void CNServer::onStep() {} // stubbed
|
||||
|
@@ -1,21 +1,21 @@
|
||||
#ifndef _CNP_HPP
|
||||
#define _CNP_HPP
|
||||
#pragma once
|
||||
|
||||
#define MAX_PACKETSIZE 8192
|
||||
#define DEBUGLOG(x) x
|
||||
#define DEBUGLOG(x) if (settings::VERBOSITY) {x};
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#ifdef _WIN32
|
||||
// windows (UNTESTED)
|
||||
// windows
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
typedef char buffer_t;
|
||||
//#define errno WSAGetLastError()
|
||||
#define OF_ERRNO WSAGetLastError()
|
||||
#define OF_EWOULD WSAEWOULDBLOCK
|
||||
#define SOCKETINVALID(x) (x == INVALID_SOCKET)
|
||||
#define SOCKETERROR(x) (x == SOCKET_ERROR)
|
||||
#else
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
typedef int SOCKET;
|
||||
typedef void buffer_t;
|
||||
#define OF_ERRNO errno
|
||||
#define OF_EWOULD EWOULDBLOCK
|
||||
#define SOCKETINVALID(x) (x < 0)
|
||||
#define SOCKETERROR(x) (x == -1)
|
||||
#endif
|
||||
@@ -39,12 +41,22 @@
|
||||
#include <list>
|
||||
#include <queue>
|
||||
|
||||
#include "Defines.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
|
||||
#include "mingw/mingw.mutex.h"
|
||||
#else
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Packets format (sent from the client):
|
||||
[4 bytes] - size of packet (including these 4 bytes!)
|
||||
[4 bytes] - size of packet including the 4 byte packet type
|
||||
[size bytes] - Encrypted packet (byte swapped && xor'd with 8 byte key; see CNSocketEncryption)
|
||||
[4 bytes] - packet type (which is a combination of the first 4 bytes of the packet and a checksum in some versions)
|
||||
[structure]
|
||||
[structure] - one member contains length of trailing data (expressed in packet-dependant structures)
|
||||
[trailing data] - optional variable-length data that only some packets make use of
|
||||
*/
|
||||
|
||||
// error checking calloc wrapper
|
||||
@@ -59,6 +71,42 @@ inline void* xmalloc(size_t sz) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// overflow-safe validation of variable-length packets
|
||||
// for outbound packets
|
||||
inline bool validOutVarPacket(size_t base, int32_t npayloads, size_t plsize) {
|
||||
// check for multiplication overflow
|
||||
if (npayloads > 0 && CN_PACKET_BUFFER_SIZE / (size_t)npayloads < plsize)
|
||||
return false;
|
||||
|
||||
// it's safe to multiply
|
||||
size_t trailing = npayloads * plsize;
|
||||
|
||||
// does it fit in a packet?
|
||||
if (base + trailing > CN_PACKET_BUFFER_SIZE)
|
||||
return false;
|
||||
|
||||
// everything is a-ok!
|
||||
return true;
|
||||
}
|
||||
|
||||
// for inbound packets
|
||||
inline bool validInVarPacket(size_t base, int32_t npayloads, size_t plsize, size_t datasize) {
|
||||
// check for multiplication overflow
|
||||
if (npayloads > 0 && CN_PACKET_BUFFER_SIZE / (size_t)npayloads < plsize)
|
||||
return false;
|
||||
|
||||
// it's safe to multiply
|
||||
size_t trailing = npayloads * plsize;
|
||||
|
||||
// make sure size is exact
|
||||
// datasize has already been validated against CN_PACKET_BUFFER_SIZE
|
||||
if (datasize != base + trailing)
|
||||
return false;
|
||||
|
||||
// everything is a-ok!
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace CNSocketEncryption {
|
||||
// you won't believe how complicated they made it in the client :facepalm:
|
||||
static constexpr const char* defaultKey = "m@rQn~W#";
|
||||
@@ -71,15 +119,17 @@ namespace CNSocketEncryption {
|
||||
int decryptData(uint8_t* buffer, uint8_t* key, int size);
|
||||
}
|
||||
|
||||
class CNPacketData {
|
||||
public:
|
||||
struct CNPacketData {
|
||||
void* buf;
|
||||
int size;
|
||||
uint32_t type;
|
||||
uint64_t key;
|
||||
|
||||
CNPacketData(void* b, uint32_t t, int l, uint64_t k);
|
||||
~CNPacketData();
|
||||
CNPacketData(void* b, uint32_t t, int l);
|
||||
};
|
||||
|
||||
enum ACTIVEKEY {
|
||||
SOCKETKEY_E,
|
||||
SOCKETKEY_FE
|
||||
};
|
||||
|
||||
class CNSocket;
|
||||
@@ -90,12 +140,15 @@ private:
|
||||
uint64_t EKey;
|
||||
uint64_t FEKey;
|
||||
int32_t readSize = 0;
|
||||
uint8_t* readBuffer = new uint8_t[MAX_PACKETSIZE];
|
||||
uint8_t readBuffer[CN_PACKET_BUFFER_SIZE];
|
||||
int readBufferIndex = 0;
|
||||
bool activelyReading = false;
|
||||
bool alive = true;
|
||||
|
||||
ACTIVEKEY activeKey;
|
||||
|
||||
bool sendData(uint8_t* data, int size);
|
||||
int recvData(buffer_t* data, int size);
|
||||
|
||||
public:
|
||||
SOCKET sock;
|
||||
@@ -107,17 +160,33 @@ public:
|
||||
void setFEKey(uint64_t k);
|
||||
uint64_t getEKey();
|
||||
uint64_t getFEKey();
|
||||
void setActiveKey(ACTIVEKEY t);
|
||||
|
||||
void kill();
|
||||
void sendPacket(CNPacketData* pak);
|
||||
void sendPacket(void* buf, uint32_t packetType, size_t size);
|
||||
void step();
|
||||
bool isAlive();
|
||||
};
|
||||
|
||||
class CNServer;
|
||||
typedef void (*TimerHandler)(CNServer* serv, uint64_t time);
|
||||
|
||||
// timer struct
|
||||
struct TimerEvent {
|
||||
TimerHandler handlr;
|
||||
uint64_t delta; // time to be added to the current time on reset
|
||||
uint64_t scheduledEvent; // time to call handlr()
|
||||
|
||||
TimerEvent(TimerHandler h, uint64_t d): handlr(h), delta(d) {
|
||||
scheduledEvent = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// in charge of accepting new connections and making sure each connection is kept alive
|
||||
class CNServer {
|
||||
protected:
|
||||
std::list<CNSocket*> connections;
|
||||
std::mutex activeCrit;
|
||||
|
||||
SOCKET sock;
|
||||
uint16_t port;
|
||||
@@ -125,6 +194,8 @@ protected:
|
||||
struct sockaddr_in address;
|
||||
void init();
|
||||
|
||||
bool active = true;
|
||||
|
||||
public:
|
||||
PacketHandler pHandler;
|
||||
|
||||
@@ -132,7 +203,9 @@ public:
|
||||
CNServer(uint16_t p);
|
||||
|
||||
void start();
|
||||
void kill();
|
||||
static void printPacket(CNPacketData *data, int type);
|
||||
virtual void newConnection(CNSocket* cns);
|
||||
virtual void killConnection(CNSocket* cns);
|
||||
virtual void onStep(); // called every 2 seconds
|
||||
};
|
||||
|
||||
#endif
|
@@ -3,31 +3,76 @@
|
||||
#include "CNShardServer.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "CNShared.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
|
||||
std::map<uint32_t, PacketHandler> CNShardServer::ShardPackets;
|
||||
std::list<TimerEvent> CNShardServer::Timers;
|
||||
|
||||
CNShardServer::CNShardServer(uint16_t p) {
|
||||
port = p;
|
||||
pHandler = &CNShardServer::handlePacket;
|
||||
REGISTER_SHARD_TIMER(keepAliveTimer, 2000);
|
||||
init();
|
||||
}
|
||||
|
||||
void CNShardServer::handlePacket(CNSocket* sock, CNPacketData* data) {
|
||||
printPacket(data, CL2FE);
|
||||
|
||||
if (ShardPackets.find(data->type) != ShardPackets.end())
|
||||
ShardPackets[data->type](sock, data);
|
||||
else
|
||||
std::cerr << "OpenFusion: SHARD UNIMPLM ERR. PacketType: " << data->type << std::endl;
|
||||
else if (settings::VERBOSITY > 0)
|
||||
std::cerr << "OpenFusion: SHARD UNIMPLM ERR. PacketType: " << Defines::p2str(CL2FE, data->type) << " (" << data->type << ")" << std::endl;
|
||||
}
|
||||
|
||||
void CNShardServer::keepAliveTimer(CNServer* serv, uint64_t currTime) {
|
||||
auto cachedPlayers = PlayerManager::players;
|
||||
|
||||
for (auto pair : cachedPlayers) {
|
||||
if (pair.second.lastHeartbeat != 0 && currTime - pair.second.lastHeartbeat > 60000) { // if the client hadn't responded in 60 seconds, its a dead connection so throw it out
|
||||
pair.first->kill();
|
||||
continue;
|
||||
}
|
||||
|
||||
// passed the heartbeat, send another
|
||||
INITSTRUCT(sP_FE2CL_REQ_LIVE_CHECK, data);
|
||||
pair.first->sendPacket((void*)&data, P_FE2CL_REQ_LIVE_CHECK, sizeof(sP_FE2CL_REQ_LIVE_CHECK));
|
||||
}
|
||||
}
|
||||
|
||||
void CNShardServer::newConnection(CNSocket* cns) {
|
||||
cns->setActiveKey(SOCKETKEY_E); // by default they accept keys encrypted with the default key
|
||||
}
|
||||
|
||||
void CNShardServer::killConnection(CNSocket* cns) {
|
||||
// remove from CNSharedData
|
||||
Player cachedPlr = PlayerManager::getPlayer(cns);
|
||||
// check if the player ever sent a REQ_PC_ENTER
|
||||
if (PlayerManager::players.find(cns) == PlayerManager::players.end())
|
||||
return;
|
||||
|
||||
// remove from CNSharedData
|
||||
int64_t key = PlayerManager::getPlayer(cns)->SerialKey;
|
||||
PlayerManager::removePlayer(cns);
|
||||
|
||||
CNSharedData::erasePlayer(cachedPlr.SerialKey);
|
||||
std::cout << U16toU8(cachedPlr.PCStyle.szFirstName) << " " << U16toU8(cachedPlr.PCStyle.szLastName) << " left" << std::endl;
|
||||
}
|
||||
CNSharedData::erasePlayer(key);
|
||||
}
|
||||
|
||||
void CNShardServer::onStep() {
|
||||
uint64_t currTime = getTime();
|
||||
|
||||
for (TimerEvent& event : Timers) {
|
||||
if (event.scheduledEvent == 0) {
|
||||
// event hasn't been queued yet, go ahead and do that
|
||||
event.scheduledEvent = currTime + event.delta;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event.scheduledEvent < currTime) {
|
||||
// timer needs to be called
|
||||
event.handlr(this, currTime);
|
||||
event.scheduledEvent = currTime + event.delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,49 +1,26 @@
|
||||
#ifndef _CNSS_HPP
|
||||
#define _CNSS_HPP
|
||||
#pragma once
|
||||
|
||||
#include "CNProtocol.hpp"
|
||||
#include "Defines.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
enum SHARDPACKETID {
|
||||
// client 2 shard
|
||||
P_CL2FE_REQ_PC_ENTER = 318767105,
|
||||
P_CL2FE_REQ_PC_LOADING_COMPLETE = 318767245,
|
||||
P_CL2FE_REQ_PC_MOVE = 318767107,
|
||||
P_CL2FE_REQ_PC_STOP = 318767108,
|
||||
P_CL2FE_REQ_PC_JUMP = 318767109,
|
||||
P_CL2FE_REQ_PC_MOVEPLATFORM = 318767168,
|
||||
P_CL2FE_REQ_PC_GOTO = 318767124,
|
||||
P_CL2FE_GM_REQ_PC_SET_VALUE = 318767211,
|
||||
P_CL2FE_REQ_SEND_FREECHAT_MESSAGE = 318767111,
|
||||
P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT = 318767184,
|
||||
|
||||
// shard 2 client
|
||||
P_FE2CL_REP_PC_ENTER_SUCC = 822083586,
|
||||
P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC = 822083833,
|
||||
P_FE2CL_PC_NEW = 822083587,
|
||||
P_FE2CL_PC_MOVE = 822083592,
|
||||
P_FE2CL_PC_STOP = 822083593,
|
||||
P_FE2CL_PC_JUMP = 822083594,
|
||||
P_FE2CL_PC_EXIT = 822083590,
|
||||
P_FE2CL_PC_MOVEPLATFORM = 822083704,
|
||||
P_FE2CL_REP_PC_GOTO_SUCC = 822083633,
|
||||
P_FE2CL_GM_REP_PC_SET_VALUE = 822083781,
|
||||
P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT = 822083730
|
||||
};
|
||||
|
||||
#define REGISTER_SHARD_PACKET(pactype, handlr) CNShardServer::ShardPackets[pactype] = handlr;
|
||||
#define REGISTER_SHARD_TIMER(handlr, delta) CNShardServer::Timers.push_back(TimerEvent(handlr, delta));
|
||||
|
||||
// WARNING: THERE CAN ONLY BE ONE OF THESE SERVERS AT A TIME!!!!!! TODO: change players & packet handlers to be non-static
|
||||
class CNShardServer : public CNServer {
|
||||
private:
|
||||
static void handlePacket(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
static void keepAliveTimer(CNServer*, uint64_t);
|
||||
|
||||
public:
|
||||
static std::map<uint32_t, PacketHandler> ShardPackets;
|
||||
static std::list<TimerEvent> Timers;
|
||||
|
||||
CNShardServer(uint16_t p);
|
||||
|
||||
void newConnection(CNSocket* cns);
|
||||
void killConnection(CNSocket* cns);
|
||||
void onStep();
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,6 +1,6 @@
|
||||
#include "CNShared.hpp"
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
|
||||
#include "mingw/mingw.mutex.h"
|
||||
#else
|
||||
#include <mutex>
|
||||
@@ -15,6 +15,8 @@ void CNSharedData::setPlayer(int64_t sk, Player& plr) {
|
||||
}
|
||||
|
||||
Player CNSharedData::getPlayer(int64_t sk) {
|
||||
std::lock_guard<std::mutex> lock(playerCrit); // the lock will be removed when the function ends
|
||||
|
||||
return players[sk];
|
||||
}
|
||||
|
||||
|
@@ -3,8 +3,7 @@
|
||||
There's some data shared between the Login Server and the Shard Server. Of course all of this needs to be thread-safe. No mucking about on this one!
|
||||
*/
|
||||
|
||||
#ifndef _CNSD_HPP
|
||||
#define _CNSD_HPP
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -19,5 +18,3 @@ namespace CNSharedData {
|
||||
Player getPlayer(int64_t sk);
|
||||
void erasePlayer(int64_t sk);
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,12 +1,19 @@
|
||||
#include "CNStructs.hpp"
|
||||
#if defined _MSC_VER
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
std::string U16toU8(char16_t* src) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
||||
return convert.to_bytes(src);
|
||||
try {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
||||
return convert.to_bytes(src);
|
||||
} catch(std::exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// returns number of char16_t that was written at des
|
||||
int U8toU16(std::string src, char16_t* des) {
|
||||
size_t U8toU16(std::string src, char16_t* des) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
||||
std::u16string tmp = convert.from_bytes(src);
|
||||
|
||||
@@ -18,7 +25,12 @@ int U8toU16(std::string src, char16_t* des) {
|
||||
}
|
||||
|
||||
uint64_t getTime() {
|
||||
#ifndef _MSC_VER
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp, NULL);
|
||||
return tp.tv_sec * 1000 + tp.tv_usec / 1000;
|
||||
#else
|
||||
std::chrono::milliseconds value = std::chrono::duration_cast<std::chrono::milliseconds>((std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now())).time_since_epoch());
|
||||
return (uint64_t)(value.count());
|
||||
#endif
|
||||
}
|
@@ -1,533 +1,46 @@
|
||||
/*
|
||||
CNStructs.hpp - defines some basic structs & useful methods for packets used by FusionFall
|
||||
|
||||
NOTE: this is missing the vast majority of packets, I have also ommitted the ERR & FAIL packets for simplicity
|
||||
/*
|
||||
CNStructs.hpp - defines some basic structs & useful methods for packets used by FusionFall based on the version defined
|
||||
*/
|
||||
|
||||
#ifndef _CNS_HPP
|
||||
#define _CNS_HPP
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// codecvt_* is deprecated in C++17 and MSVC will throw an annoying warning because of that.
|
||||
// Defining this before anything else to silence it.
|
||||
#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
// Can't use this in MSVC.
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
|
||||
// yes this is ugly, but this is needed to zero out the memory so we don't have random stackdata in our structs.
|
||||
#define INITSTRUCT(T, x) T x; \
|
||||
memset(&x, 0, sizeof(T));
|
||||
|
||||
// TODO: rewrite U16toU8 & U8toU16 to not use codecvt
|
||||
|
||||
std::string U16toU8(char16_t* src);
|
||||
|
||||
// returns number of char16_t that was written at des
|
||||
int U8toU16(std::string src, char16_t* des);
|
||||
|
||||
size_t U8toU16(std::string src, char16_t* des); // returns number of char16_t that was written at des
|
||||
uint64_t getTime();
|
||||
|
||||
//#define CNPROTO_VERSION_0728
|
||||
|
||||
#ifdef CNPROTO_VERSION_0728
|
||||
#define AEQUIP_COUNT 12
|
||||
// The PROTOCOL_VERSION definition is defined by the build system.
|
||||
#if !defined(PROTOCOL_VERSION)
|
||||
#include "structs/0104.hpp"
|
||||
#elif PROTOCOL_VERSION == 728
|
||||
#include "structs/0728.hpp"
|
||||
#elif PROTOCOL_VERSION == 104
|
||||
#include "structs/0104.hpp"
|
||||
#else
|
||||
#define AEQUIP_COUNT 9
|
||||
#error Invalid PROTOCOL_VERSION
|
||||
#endif
|
||||
|
||||
// ========================================================[[ General Purpose ]]========================================================
|
||||
|
||||
// sets the same byte alignment as the structs in the client
|
||||
#pragma pack(push, 4)
|
||||
struct sPCStyle {
|
||||
int64_t iPC_UID;
|
||||
int8_t iNameCheck;
|
||||
|
||||
char16_t szFirstName[9];
|
||||
char16_t szLastName[17];
|
||||
|
||||
int8_t iGender;
|
||||
int8_t iFaceStyle;
|
||||
int8_t iHairStyle;
|
||||
int8_t iHairColor;
|
||||
int8_t iSkinColor;
|
||||
int8_t iEyeColor;
|
||||
int8_t iHeight;
|
||||
int8_t iBody;
|
||||
int32_t iClass;
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct sPCStyle2 {
|
||||
int8_t iAppearanceFlag;
|
||||
int8_t iTutorialFlag;
|
||||
int8_t iPayzoneFlag;
|
||||
|
||||
sPCStyle2() {}
|
||||
sPCStyle2(int8_t a, int8_t t, int8_t p):
|
||||
iAppearanceFlag(a), iTutorialFlag(t), iPayzoneFlag(p) {}
|
||||
};
|
||||
|
||||
#pragma pack(2)
|
||||
struct sOnItem {
|
||||
int16_t iEquipHandID;
|
||||
int16_t iEquipUBID;
|
||||
int16_t iEquipLBID;
|
||||
int16_t iEquipFootID;
|
||||
int16_t iEquipHeadID;
|
||||
int16_t iEquipFaceID;
|
||||
int16_t iEquipBackID;
|
||||
};
|
||||
|
||||
struct sOnItem_Index {
|
||||
int16_t iEquipUBID_index;
|
||||
int16_t iEquipLBID_index;
|
||||
int16_t iEquipFootID_index;
|
||||
int16_t iFaceStyle;
|
||||
int16_t iHairStyle;
|
||||
};
|
||||
|
||||
struct sNano {
|
||||
int16_t iID;
|
||||
int16_t iSkillID;
|
||||
int16_t iStamina;
|
||||
};
|
||||
|
||||
#pragma pack(4)
|
||||
struct sItemBase {
|
||||
int16_t iType;
|
||||
int16_t iID;
|
||||
int32_t iOpt;
|
||||
int32_t iTimeLimit;
|
||||
|
||||
#ifdef CNPROTO_VERSION_0728
|
||||
int32_t iSerial;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct sTimeBuff {
|
||||
uint64_t iTimeLimit;
|
||||
uint64_t iTimeDuration;
|
||||
|
||||
int32_t iTimeRepeat;
|
||||
int32_t iValue;
|
||||
int32_t iConfirmNum;
|
||||
};
|
||||
|
||||
struct sRunningQuest {
|
||||
int32_t m_aCurrTaskID;
|
||||
|
||||
int32_t m_aKillNPCID[3];
|
||||
int32_t m_aKillNPCCount[3];
|
||||
int32_t m_aNeededItemID[3];
|
||||
int32_t m_aNeededItemCount[3];
|
||||
};
|
||||
|
||||
struct sPCLoadData2CL {
|
||||
int16_t iUserLevel;
|
||||
sPCStyle PCStyle;
|
||||
sPCStyle2 PCStyle2;
|
||||
|
||||
int16_t iLevel;
|
||||
int16_t iMentor;
|
||||
int16_t iMentorCount;
|
||||
int32_t iHP;
|
||||
int32_t iBatteryW;
|
||||
int32_t iBatteryN;
|
||||
int32_t iCandy;
|
||||
int32_t iFusionMatter;
|
||||
int8_t iSpecialState;
|
||||
int32_t iMapNum;
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
int32_t iAngle;
|
||||
|
||||
sItemBase aEquip[AEQUIP_COUNT];
|
||||
sItemBase aInven[50];
|
||||
sItemBase aQInven[50];
|
||||
|
||||
sNano aNanoBank[37];
|
||||
|
||||
int16_t aNanoSlots[3];
|
||||
|
||||
int16_t iActiveNanoSlotNum;
|
||||
int32_t iConditionBitFlag;
|
||||
int32_t eCSTB___Add;
|
||||
|
||||
sTimeBuff TimeBuff;
|
||||
|
||||
int64_t aQuestFlag[32];
|
||||
int64_t aRepeatQuestFlag[8];
|
||||
|
||||
sRunningQuest aRunningQuest[9];
|
||||
|
||||
int32_t iCurrentMissionID;
|
||||
int32_t iWarpLocationFlag;
|
||||
|
||||
int64_t aWyvernLocationFlag[2];
|
||||
|
||||
int32_t iBuddyWarpTime;
|
||||
int32_t iFatigue;
|
||||
int32_t iFatigue_Level;
|
||||
int32_t iFatigueRate;
|
||||
int64_t iFirstUseFlag1;
|
||||
int64_t iFirstUseFlag2;
|
||||
|
||||
int32_t aiPCSkill[33];
|
||||
|
||||
sPCLoadData2CL() {};
|
||||
};
|
||||
|
||||
struct sPCAppearanceData {
|
||||
int32_t iID;
|
||||
sPCStyle PCStyle;
|
||||
|
||||
int32_t iConditionBitFlag;
|
||||
int8_t iPCState;
|
||||
int8_t iSpecialState;
|
||||
int16_t iLv;
|
||||
int32_t iHP;
|
||||
|
||||
int32_t iMapNum;
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
int32_t iAngle;
|
||||
|
||||
sItemBase ItemEquip[AEQUIP_COUNT];
|
||||
sNano Nano;
|
||||
|
||||
int32_t eRT;
|
||||
};
|
||||
|
||||
// ========================================================[[ Client2LoginServer packets ]]========================================================
|
||||
|
||||
#pragma pack(4)
|
||||
struct sP_CL2LS_REQ_LOGIN {
|
||||
char16_t szID[33];
|
||||
char16_t szPassword[33];
|
||||
|
||||
int32_t iClientVerA;
|
||||
int32_t iClientVerB;
|
||||
int32_t iClientVerC;
|
||||
|
||||
int32_t iLoginType;
|
||||
|
||||
uint8_t szCookie_TEGid[64];
|
||||
uint8_t szCookie_authid[255];
|
||||
};
|
||||
|
||||
struct sP_CL2LS_REQ_CHECK_CHAR_NAME {
|
||||
int32_t iFNCode;
|
||||
int32_t iLNCode;
|
||||
int32_t iMNCode;
|
||||
|
||||
char16_t szFirstName[9];
|
||||
char16_t szLastName[17];
|
||||
};
|
||||
|
||||
struct sP_CL2LS_REQ_SAVE_CHAR_NAME {
|
||||
int8_t iSlotNum;
|
||||
int8_t iGender;
|
||||
int32_t iFNCode;
|
||||
int32_t iLNCode;
|
||||
int32_t iMNCode;
|
||||
|
||||
char16_t szFirstName[9];
|
||||
char16_t szLastName[17];
|
||||
};
|
||||
|
||||
struct sP_CL2LS_REQ_CHAR_CREATE {
|
||||
sPCStyle PCStyle;
|
||||
sOnItem sOn_Item;
|
||||
sOnItem_Index sOn_Item_Index;
|
||||
};
|
||||
|
||||
struct sP_CL2LS_REQ_CHAR_SELECT {
|
||||
int64_t iPC_UID;
|
||||
};
|
||||
|
||||
struct sP_CL2LS_REP_LIVE_CHECK {
|
||||
int32_t unused;
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct sP_CL2LS_REQ_SHARD_SELECT {
|
||||
int8_t iShardNum;
|
||||
};
|
||||
|
||||
struct sP_CL2LS_REQ_SHARD_LIST_INFO {
|
||||
uint8_t unused;
|
||||
};
|
||||
|
||||
// ========================================================[[ LoginServer2Client packets ]]========================================================
|
||||
|
||||
#pragma pack(4)
|
||||
struct sP_LS2CL_REP_LOGIN_SUCC {
|
||||
int8_t iCharCount;
|
||||
int8_t iSlotNum;
|
||||
int8_t iPaymentFlag;
|
||||
int8_t iTempForPacking4; // UNUSED
|
||||
uint64_t uiSvrTime; // UNIX timestamp
|
||||
|
||||
char16_t szID[33];
|
||||
|
||||
uint32_t iOpenBetaFlag;
|
||||
};
|
||||
|
||||
#pragma pack(2)
|
||||
struct sP_LS2CL_REP_CHECK_CHAR_NAME_SUCC {
|
||||
char16_t szFirstName[9];
|
||||
char16_t szLastName[17];
|
||||
};
|
||||
|
||||
#pragma pack(4)
|
||||
struct sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC {
|
||||
int64_t iPC_UID;
|
||||
int8_t iSlotNum;
|
||||
int8_t iGender;
|
||||
|
||||
char16_t szFirstName[9];
|
||||
char16_t szLastName[17];
|
||||
};
|
||||
|
||||
struct sP_LS2CL_REP_CHAR_CREATE_SUCC {
|
||||
int16_t iLevel;
|
||||
sPCStyle PC_Style;
|
||||
sPCStyle2 PC_Style2;
|
||||
sOnItem sOn_Item;
|
||||
};
|
||||
|
||||
struct sP_LS2CL_REP_CHAR_INFO {
|
||||
int8_t iSlot;
|
||||
int16_t iLevel;
|
||||
|
||||
sPCStyle sPC_Style;
|
||||
sPCStyle2 sPC_Style2;
|
||||
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
|
||||
sItemBase aEquip[AEQUIP_COUNT];
|
||||
};
|
||||
|
||||
struct sP_LS2CL_REP_SHARD_SELECT_SUCC {
|
||||
uint8_t g_FE_ServerIP[16]; // Ascii
|
||||
int32_t g_FE_ServerPort;
|
||||
int64_t iEnterSerialKey;
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct sP_LS2CL_REP_CHAR_SELECT_SUCC {
|
||||
int8_t unused;
|
||||
};
|
||||
|
||||
struct sP_LS2CL_REP_SHARD_LIST_INFO_SUCC {
|
||||
uint8_t aShardConnectFlag[27];
|
||||
};
|
||||
|
||||
|
||||
// ========================================================[[ Client2ShardServer packets ]]========================================================
|
||||
|
||||
#pragma pack(4)
|
||||
struct sP_CL2FE_REQ_PC_ENTER {
|
||||
char16_t szID[33];
|
||||
int32_t iTempValue;
|
||||
int64_t iEnterSerialKey;
|
||||
};
|
||||
|
||||
|
||||
struct sP_CL2FE_REQ_PC_LOADING_COMPLETE {
|
||||
int32_t iPC_ID;
|
||||
};
|
||||
|
||||
struct sP_CL2FE_REQ_PC_MOVE {
|
||||
uint64_t iCliTime;
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
float fVX;
|
||||
float fVY;
|
||||
float fVZ;
|
||||
int32_t iAngle;
|
||||
uint8_t cKeyValue;
|
||||
int32_t iSpeed;
|
||||
};
|
||||
|
||||
struct sP_CL2FE_REQ_PC_STOP {
|
||||
uint64_t iCliTime;
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
};
|
||||
|
||||
struct sP_CL2FE_REQ_PC_JUMP {
|
||||
uint64_t iCliTime;
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
int32_t iVX;
|
||||
int32_t iVY;
|
||||
int32_t iVZ;
|
||||
int32_t iAngle;
|
||||
uint8_t cKeyValue;
|
||||
int32_t iSpeed;
|
||||
};
|
||||
|
||||
struct sP_CL2FE_REQ_PC_MOVEPLATFORM {
|
||||
uint64_t iCliTime;
|
||||
|
||||
int32_t iLcX;
|
||||
int32_t iLcY;
|
||||
int32_t iLcZ;
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
|
||||
float fVX;
|
||||
float fVY;
|
||||
float fVZ;
|
||||
|
||||
int32_t bDown;
|
||||
uint32_t iPlatformID;
|
||||
int32_t iAngle;
|
||||
uint32_t cKeyValue;
|
||||
int32_t iSpeed;
|
||||
};
|
||||
|
||||
struct sP_CL2FE_REQ_PC_GOTO {
|
||||
int32_t iToX;
|
||||
int32_t iToY;
|
||||
int32_t iToZ;
|
||||
};
|
||||
|
||||
struct sP_CL2FE_GM_REQ_PC_SET_VALUE {
|
||||
int32_t iPC_ID;
|
||||
int32_t iSetValueType;
|
||||
int32_t iSetValue;
|
||||
};
|
||||
|
||||
struct sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE {
|
||||
char16_t szFreeChat[128];
|
||||
int32_t iEmoteCode;
|
||||
};
|
||||
|
||||
struct sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT {
|
||||
int32_t iID_From;
|
||||
int32_t iEmoteCode;
|
||||
};
|
||||
|
||||
// ========================================================[[ ShardServer2Client packets ]]========================================================
|
||||
|
||||
struct sP_FE2CL_REP_PC_ENTER_SUCC {
|
||||
int32_t iID;
|
||||
sPCLoadData2CL PCLoadData2CL;
|
||||
uint64_t uiSvrTime;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC {
|
||||
int32_t iPC_ID;
|
||||
};
|
||||
|
||||
// literally just a wrapper for a sPCAppearanceData struct :/
|
||||
struct sP_FE2CL_PC_NEW {
|
||||
sPCAppearanceData PCAppearanceData;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_PC_MOVE {
|
||||
uint64_t iCliTime;
|
||||
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
float fVX;
|
||||
float fVY;
|
||||
float fVZ;
|
||||
int32_t iAngle;
|
||||
uint8_t cKeyValue;
|
||||
|
||||
int32_t iSpeed;
|
||||
|
||||
int32_t iID;
|
||||
|
||||
uint64_t iSvrTime;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_PC_STOP {
|
||||
uint64_t iCliTime;
|
||||
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
int32_t iID;
|
||||
|
||||
uint64_t iSvrTime;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_PC_JUMP {
|
||||
uint64_t iCliTime;
|
||||
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
int32_t iVX;
|
||||
int32_t iVY;
|
||||
int32_t iVZ;
|
||||
int32_t iAngle;
|
||||
uint8_t cKeyValue;
|
||||
int32_t iSpeed;
|
||||
int32_t iID;
|
||||
|
||||
uint64_t iSvrTime;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_PC_MOVEPLATFORM {
|
||||
uint64_t iCliTime;
|
||||
|
||||
int32_t iLcX;
|
||||
int32_t iLcY;
|
||||
int32_t iLcZ;
|
||||
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
|
||||
float fVX;
|
||||
float fVY;
|
||||
float fVZ;
|
||||
|
||||
int32_t bDown;
|
||||
uint32_t iPlatformID;
|
||||
int32_t iAngle;
|
||||
int8_t cKeyValue;
|
||||
int32_t iSpeed;
|
||||
int32_t iPC_ID;
|
||||
uint64_t iSvrTime;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_GM_REP_PC_SET_VALUE {
|
||||
int32_t iPC_ID;
|
||||
int32_t iSetValueType;
|
||||
int32_t iSetValue;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_PC_EXIT {
|
||||
int32_t iID;
|
||||
int32_t iExitType;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_REP_PC_GOTO_SUCC {
|
||||
int32_t iX;
|
||||
int32_t iY;
|
||||
int32_t iZ;
|
||||
};
|
||||
|
||||
struct sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT {
|
||||
int32_t iID_From;
|
||||
int32_t iEmoteCode;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#endif
|
@@ -6,32 +6,62 @@
|
||||
void ChatManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_FREECHAT_MESSAGE, chatHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT, emoteHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_MENUCHAT_MESSAGE, menuChatHandler);
|
||||
}
|
||||
|
||||
void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE*)data->buf;
|
||||
PlayerView plr = PlayerManager::players[sock];
|
||||
|
||||
// stubbed for now
|
||||
// send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, resp);
|
||||
memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat));
|
||||
resp.iPC_ID = plr.plr->iID;
|
||||
resp.iEmoteCode = chat->iEmoteCode;
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC));
|
||||
|
||||
// send to visible players
|
||||
for (CNSocket* otherSock : plr.viewable) {
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC));
|
||||
}
|
||||
}
|
||||
void ChatManager::menuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE*)data->buf;
|
||||
PlayerView plr = PlayerManager::players[sock];
|
||||
|
||||
// send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, resp);
|
||||
memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat));
|
||||
resp.iPC_ID = PlayerManager::players[sock].plr->iID;
|
||||
resp.iEmoteCode = chat->iEmoteCode;
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC));
|
||||
|
||||
// send to visible players
|
||||
for (CNSocket* otherSock : plr.viewable) {
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC));
|
||||
}
|
||||
}
|
||||
void ChatManager::emoteHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
// you can dance with friends!!!!!!!!
|
||||
|
||||
sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT* emote = (sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT*)data->buf;
|
||||
|
||||
PlayerView plr = PlayerManager::players[sock];
|
||||
|
||||
// send to client
|
||||
sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT* resp = (sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT*)xmalloc(sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT));
|
||||
resp->iEmoteCode = emote->iEmoteCode;
|
||||
resp->iID_From = plr.plr.iID;
|
||||
sock->sendPacket(new CNPacketData((void*)resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT), sock->getFEKey()));
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, resp);
|
||||
resp.iEmoteCode = emote->iEmoteCode;
|
||||
resp.iID_From = plr.plr->iID;
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT));
|
||||
|
||||
// send to visible players (players within render distance)
|
||||
for (CNSocket* otherSock : plr.viewable) {
|
||||
resp = (sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT*)xmalloc(sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT));
|
||||
resp->iEmoteCode = emote->iEmoteCode;
|
||||
resp->iID_From = plr.plr.iID;
|
||||
otherSock->sendPacket(new CNPacketData((void*)resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT), otherSock->getFEKey()));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT));
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#ifndef _CM_HPP
|
||||
#define _CM_HPP
|
||||
#pragma once
|
||||
|
||||
#include "CNShardServer.hpp"
|
||||
|
||||
@@ -8,6 +7,5 @@ namespace ChatManager {
|
||||
|
||||
void chatHandler(CNSocket* sock, CNPacketData* data);
|
||||
void emoteHandler(CNSocket* sock, CNPacketData* data);
|
||||
void menuChatHandler(CNSocket* sock, CNPacketData* data);
|
||||
}
|
||||
|
||||
#endif
|
131
src/CombatManager.cpp
Normal file
131
src/CombatManager.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "CombatManager.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "NPCManager.hpp"
|
||||
#include "ItemManager.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void CombatManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ATTACK_NPCs, pcAttackNpcs);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_COMBAT_BEGIN, combatBegin);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_COMBAT_END, combatEnd);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_DOT_DAMAGE_ONOFF, dotDamageOnOff);
|
||||
}
|
||||
|
||||
void CombatManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
||||
sP_CL2FE_REQ_PC_ATTACK_NPCs* pkt = (sP_CL2FE_REQ_PC_ATTACK_NPCs*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity check
|
||||
if (!validInVarPacket(sizeof(sP_CL2FE_REQ_PC_ATTACK_NPCs), pkt->iNPCCnt, sizeof(int32_t), data->size)) {
|
||||
std::cout << "[WARN] bad sP_CL2FE_REQ_PC_ATTACK_NPCs packet size\n";
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_PC_ATTACK_NPCs));
|
||||
|
||||
/*
|
||||
* Due to the possibility of multiplication overflow (and regular buffer overflow),
|
||||
* both incoming and outgoing variable-length packets must be validated, at least if
|
||||
* the number of trailing structs isn't well known (ie. it's from the client).
|
||||
*/
|
||||
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC), pkt->iNPCCnt, sizeof(sAttackResult))) {
|
||||
std::cout << "[WARN] bad sP_FE2CL_PC_ATTACK_NPCs_SUCC packet size\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize response struct
|
||||
size_t resplen = sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC) + pkt->iNPCCnt * sizeof(sAttackResult);
|
||||
uint8_t respbuf[4096];
|
||||
|
||||
memset(respbuf, 0, resplen);
|
||||
|
||||
sP_FE2CL_PC_ATTACK_NPCs_SUCC *resp = (sP_FE2CL_PC_ATTACK_NPCs_SUCC*)respbuf;
|
||||
sAttackResult *respdata = (sAttackResult*)(respbuf+sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC));
|
||||
|
||||
resp->iNPCCnt = pkt->iNPCCnt;
|
||||
|
||||
for (int i = 0; i < pkt->iNPCCnt; i++) {
|
||||
if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) {
|
||||
// not sure how to best handle this
|
||||
std::cout << "[WARN] pcAttackNpcs: mob ID not found" << std::endl;
|
||||
return;
|
||||
}
|
||||
BaseNPC& mob = NPCManager::NPCs[pktdata[i]];
|
||||
|
||||
mob.appearanceData.iHP -= 100;
|
||||
|
||||
if (mob.appearanceData.iHP <= 0)
|
||||
giveReward(sock);
|
||||
// TODO: despawn mobs when they die
|
||||
|
||||
respdata[i].iID = mob.appearanceData.iNPC_ID;
|
||||
respdata[i].iDamage = 100;
|
||||
respdata[i].iHP = mob.appearanceData.iHP;
|
||||
respdata[i].iHitFlag = 2;
|
||||
}
|
||||
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs_SUCC, resplen);
|
||||
|
||||
// a bit of a hack: these are the same size, so we can reuse the output packet
|
||||
assert(sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC) == sizeof(sP_FE2CL_PC_ATTACK_NPCs));
|
||||
sP_FE2CL_PC_ATTACK_NPCs *resp1 = (sP_FE2CL_PC_ATTACK_NPCs*)respbuf;
|
||||
|
||||
resp1->iPC_ID = plr->iID;
|
||||
|
||||
// send to other players
|
||||
for (CNSocket *s : PlayerManager::players[sock].viewable) {
|
||||
if (s == sock)
|
||||
continue;
|
||||
|
||||
s->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs, resplen);
|
||||
}
|
||||
}
|
||||
|
||||
void CombatManager::combatBegin(CNSocket *sock, CNPacketData *data) {} // stub
|
||||
void CombatManager::combatEnd(CNSocket *sock, CNPacketData *data) {} // stub
|
||||
void CombatManager::dotDamageOnOff(CNSocket *sock, CNPacketData *data) {} // stub
|
||||
|
||||
void CombatManager::giveReward(CNSocket *sock) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||
assert(resplen < CN_PACKET_BUFFER_SIZE);
|
||||
// we know it's only one trailing struct, so we can skip full validation
|
||||
|
||||
uint8_t respbuf[resplen]; // not a variable length array, don't worry
|
||||
sP_FE2CL_REP_REWARD_ITEM *reward = (sP_FE2CL_REP_REWARD_ITEM *)respbuf;
|
||||
sItemReward *item = (sItemReward *)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
||||
|
||||
// don't forget to zero the buffer!
|
||||
memset(respbuf, 0, resplen);
|
||||
|
||||
// update player
|
||||
plr->money += 50;
|
||||
plr->fusionmatter += 70;
|
||||
|
||||
// simple rewards
|
||||
reward->m_iCandy = plr->money;
|
||||
reward->m_iFusionMatter = plr->fusionmatter;
|
||||
reward->iFatigue = 100; // prevents warning message
|
||||
reward->iFatigue_Level = 1;
|
||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||
|
||||
int slot = ItemManager::findFreeSlot(plr);
|
||||
if (slot == -1) {
|
||||
// no room for an item, but you still get FM and taros
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
||||
} else {
|
||||
// item reward
|
||||
item->sItem.iType = 9;
|
||||
item->sItem.iID = 1;
|
||||
item->iSlotNum = slot;
|
||||
item->eIL = 1; // Inventory Location. 1 means player inventory.
|
||||
|
||||
// update player
|
||||
plr->Inven[slot] = item->sItem;
|
||||
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||
}
|
||||
}
|
16
src/CombatManager.hpp
Normal file
16
src/CombatManager.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "CNProtocol.hpp"
|
||||
#include "CNShared.hpp"
|
||||
#include "CNShardServer.hpp"
|
||||
|
||||
namespace CombatManager {
|
||||
void init();
|
||||
|
||||
void pcAttackNpcs(CNSocket *sock, CNPacketData *data);
|
||||
void combatBegin(CNSocket *sock, CNPacketData *data);
|
||||
void combatEnd(CNSocket *sock, CNPacketData *data);
|
||||
void dotDamageOnOff(CNSocket *sock, CNPacketData *data);
|
||||
|
||||
void giveReward(CNSocket *sock);
|
||||
}
|
357
src/Database.cpp
Normal file
357
src/Database.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
#include "Database.hpp"
|
||||
#include "contrib/bcrypt/BCrypt.hpp"
|
||||
#include "CNProtocol.hpp"
|
||||
#include <string>
|
||||
#include "contrib/JSON.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "Player.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "contrib/sqlite/sqlite_orm.h"
|
||||
|
||||
using namespace sqlite_orm;
|
||||
|
||||
# pragma region DatabaseScheme
|
||||
auto db = make_storage("database.db",
|
||||
make_table("Accounts",
|
||||
make_column("AccountID", &Database::Account::AccountID, autoincrement(), primary_key()),
|
||||
make_column("Login", &Database::Account::Login),
|
||||
make_column("Password", &Database::Account::Password),
|
||||
make_column("Selected", &Database::Account::Selected)
|
||||
),
|
||||
make_table("Players",
|
||||
make_column("PlayerID", &Database::DbPlayer::PlayerID, autoincrement(), primary_key()),
|
||||
make_column("AccountID", &Database::DbPlayer::AccountID),
|
||||
make_column("Slot", &Database::DbPlayer::slot),
|
||||
make_column("Firstname", &Database::DbPlayer::FirstName),
|
||||
make_column("LastName", &Database::DbPlayer::LastName),
|
||||
make_column("Level", &Database::DbPlayer::Level),
|
||||
make_column("AppearanceFlag", &Database::DbPlayer::AppearanceFlag),
|
||||
make_column("TutorialFlag", &Database::DbPlayer::TutorialFlag),
|
||||
make_column("PayZoneFlag", &Database::DbPlayer::PayZoneFlag),
|
||||
make_column("XCoordinates", &Database::DbPlayer::x_coordinates),
|
||||
make_column("YCoordinates", &Database::DbPlayer::y_coordinates),
|
||||
make_column("ZCoordinates", &Database::DbPlayer::z_coordinates),
|
||||
make_column("Body", &Database::DbPlayer::Body),
|
||||
make_column("Class", &Database::DbPlayer::Class),
|
||||
make_column("EquipFoot", &Database::DbPlayer::EquipFoot),
|
||||
make_column("EquipLB", &Database::DbPlayer::EquipLB),
|
||||
make_column("EquipUB", &Database::DbPlayer::EquipUB),
|
||||
make_column("EquipWeapon1", &Database::DbPlayer::EquipWeapon1),
|
||||
make_column("EyeColor", &Database::DbPlayer::EyeColor),
|
||||
make_column("FaceStyle", &Database::DbPlayer::FaceStyle),
|
||||
make_column("Gender", &Database::DbPlayer::Gender),
|
||||
make_column("HP", &Database::DbPlayer::HP),
|
||||
make_column("HairColor", &Database::DbPlayer::HairColor),
|
||||
make_column("HairStyle", &Database::DbPlayer::HairStyle),
|
||||
make_column("Height", &Database::DbPlayer::Height),
|
||||
make_column("NameCheck", &Database::DbPlayer::NameCheck),
|
||||
make_column("SkinColor", &Database::DbPlayer::SkinColor),
|
||||
make_column("isGM", &Database::DbPlayer::isGM),
|
||||
make_column("FusionMatter", &Database::DbPlayer::FusionMatter),
|
||||
make_column("Taros", &Database::DbPlayer::Taros)
|
||||
),
|
||||
make_table("Inventory",
|
||||
make_column("AccountID", &Database::Inventory::AccountID, primary_key())
|
||||
)
|
||||
);
|
||||
|
||||
# pragma endregion DatabaseScheme
|
||||
|
||||
#pragma region LoginServer
|
||||
|
||||
void Database::open()
|
||||
{
|
||||
//this parameter means it will try to preserve data during migration
|
||||
bool preserve = true;
|
||||
db.sync_schema(preserve);
|
||||
DEBUGLOG(
|
||||
std::cout << "[DB] Database in operation" << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
int Database::addAccount(std::string login, std::string password)
|
||||
{
|
||||
password = BCrypt::generateHash(password);
|
||||
Account x = {};
|
||||
x.Login = login;
|
||||
x.Password = password;
|
||||
x.Selected = 1;
|
||||
return db.insert(x);
|
||||
}
|
||||
|
||||
void Database::updateSelected(int accountId, int slot)
|
||||
{
|
||||
Account acc = db.get<Account>(accountId);
|
||||
acc.Selected = slot;
|
||||
db.update(acc);
|
||||
}
|
||||
|
||||
std::unique_ptr<Database::Account> Database::findAccount(std::string login)
|
||||
{
|
||||
//this is awful, I've tried everything to improve it
|
||||
auto find = db.get_all<Account>(
|
||||
where(c(&Account::Login) == login), limit(1));
|
||||
if (find.empty())
|
||||
return nullptr;
|
||||
return
|
||||
std::unique_ptr<Account>(new Account(find.front()));
|
||||
}
|
||||
|
||||
bool Database::isNameFree(sP_CL2LS_REQ_CHECK_CHAR_NAME* nameCheck)
|
||||
{
|
||||
//TODO: add colate nocase
|
||||
std::string First = U16toU8(nameCheck->szFirstName);
|
||||
std::string Last = U16toU8(nameCheck->szLastName);
|
||||
return
|
||||
(db.get_all<DbPlayer>
|
||||
(where((c(&DbPlayer::FirstName) == First)
|
||||
and (c(&DbPlayer::LastName) == Last)))
|
||||
.empty());
|
||||
}
|
||||
|
||||
int Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID)
|
||||
{
|
||||
DbPlayer create = {};
|
||||
//save packet data
|
||||
create.FirstName = U16toU8(save->szFirstName);
|
||||
create.LastName = U16toU8(save->szLastName);
|
||||
create.slot = save->iSlotNum;
|
||||
create.AccountID = AccountID;
|
||||
//set flags
|
||||
create.AppearanceFlag = 0;
|
||||
create.TutorialFlag = 0;
|
||||
create.PayZoneFlag = 0;
|
||||
//set namecheck based on setting
|
||||
if (settings::APPROVEALLNAMES || save->iFNCode)
|
||||
create.NameCheck = 1;
|
||||
else
|
||||
create.NameCheck = 0;
|
||||
//create default body character
|
||||
create.Body= 0;
|
||||
create.Class= 0;
|
||||
create.EquipFoot= 0;
|
||||
create.EquipLB= 0;
|
||||
create.EquipUB= 0;
|
||||
create.EquipWeapon1= 0;
|
||||
create.EquipWeapon2= 0;
|
||||
create.EyeColor= 1;
|
||||
create.FaceStyle= 1;
|
||||
create.Gender= 1;
|
||||
create.HP= 1000;
|
||||
create.HairColor= 1;
|
||||
create.HairStyle = 1;
|
||||
create.Height= 0;
|
||||
create.Level= 1;
|
||||
create.SkinColor= 1;
|
||||
create.isGM = false;
|
||||
//commented and disabled for now
|
||||
//if (U16toU8(save->szFirstName) == settings::GMPASS) {
|
||||
// create.isGM = true;
|
||||
//}
|
||||
|
||||
create.FusionMatter= 0;
|
||||
create.Taros= 0;
|
||||
create.x_coordinates = settings::SPAWN_X;
|
||||
create.y_coordinates= settings::SPAWN_Y;
|
||||
create.z_coordinates= settings::SPAWN_Z;
|
||||
return db.insert(create);
|
||||
}
|
||||
|
||||
void Database::finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character)
|
||||
{
|
||||
DbPlayer finish = getDbPlayerById(character->PCStyle.iPC_UID);
|
||||
finish.AppearanceFlag = 1;
|
||||
finish.Body = character->PCStyle.iBody;
|
||||
finish.Class = character->PCStyle.iClass;
|
||||
finish.EquipFoot = character->sOn_Item.iEquipFootID;
|
||||
finish.EquipLB = character->sOn_Item.iEquipLBID;
|
||||
finish.EquipUB = character->sOn_Item.iEquipUBID;
|
||||
finish.EyeColor = character->PCStyle.iEyeColor;
|
||||
finish.FaceStyle = character->PCStyle.iFaceStyle;
|
||||
finish.Gender = character->PCStyle.iGender;
|
||||
finish.HairColor = character->PCStyle.iHairColor;
|
||||
finish.HairStyle = character->PCStyle.iHairStyle;
|
||||
finish.Height = character->PCStyle.iHeight;
|
||||
finish.Level = 1;
|
||||
finish.SkinColor = character->PCStyle.iSkinColor;
|
||||
db.update(finish);
|
||||
}
|
||||
|
||||
void Database::finishTutorial(int PlayerID)
|
||||
{
|
||||
DbPlayer finish = getDbPlayerById(PlayerID);
|
||||
finish.TutorialFlag = 1;
|
||||
//equip lightning gun
|
||||
finish.EquipWeapon1 = 328;
|
||||
db.update(finish);
|
||||
}
|
||||
|
||||
int Database::deleteCharacter(int characterID)
|
||||
{
|
||||
auto find =
|
||||
db.get_all<DbPlayer>(where(c(&DbPlayer::PlayerID) == characterID));
|
||||
int slot = find.front().slot;
|
||||
db.remove<DbPlayer>(find.front().PlayerID);
|
||||
return slot;
|
||||
}
|
||||
|
||||
std::vector <Player> Database::getCharacters(int UserID)
|
||||
{
|
||||
std::vector<DbPlayer>characters =
|
||||
db.get_all<DbPlayer>(where
|
||||
(c(&DbPlayer::AccountID) == UserID));
|
||||
//parsing DbPlayer to Player
|
||||
std::vector<Player> result = std::vector<Player>();
|
||||
for (auto &character : characters) {
|
||||
Player toadd = DbToPlayer(character);
|
||||
result.push_back(
|
||||
toadd
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Database::evaluateCustomName(int characterID, CUSTOMNAME decision) {
|
||||
DbPlayer player = getDbPlayerById(characterID);
|
||||
player.NameCheck = (int)decision;
|
||||
db.update(player);
|
||||
}
|
||||
|
||||
void Database::changeName(sP_CL2LS_REQ_CHANGE_CHAR_NAME* save) {
|
||||
DbPlayer Player = getDbPlayerById(save->iPCUID);
|
||||
Player.FirstName = U16toU8(save->szFirstName);
|
||||
Player.LastName = U16toU8(save->szLastName);
|
||||
if (settings::APPROVEALLNAMES || save->iFNCode)
|
||||
Player.NameCheck = 1;
|
||||
else
|
||||
Player.NameCheck = 0;
|
||||
db.update(Player);
|
||||
}
|
||||
|
||||
Database::DbPlayer Database::playerToDb(Player player)
|
||||
{
|
||||
DbPlayer result = {}; // fixes some weird memory errors, this zeros out the members (not the padding inbetween though)
|
||||
|
||||
result.PlayerID = player.iID;
|
||||
result.AccountID = player.accountId;
|
||||
result.AppearanceFlag = player.PCStyle2.iAppearanceFlag;
|
||||
result.Body = player.PCStyle.iBody;
|
||||
result.Class = player.PCStyle.iClass;
|
||||
//equipment
|
||||
result.EyeColor = player.PCStyle.iEyeColor;
|
||||
result.FaceStyle = player.PCStyle.iFaceStyle;
|
||||
result.FirstName = U16toU8( player.PCStyle.szFirstName);
|
||||
//fm
|
||||
result.Gender = player.PCStyle.iGender;
|
||||
result.HairColor = player.PCStyle.iHairColor;
|
||||
result.HairStyle = player.PCStyle.iHairStyle;
|
||||
result.Height = player.PCStyle.iHeight;
|
||||
result.HP = player.HP;
|
||||
result.isGM = player.IsGM;
|
||||
result.LastName = U16toU8(player.PCStyle.szLastName);
|
||||
result.Level = player.level;
|
||||
result.NameCheck = player.PCStyle.iNameCheck;
|
||||
result.PayZoneFlag = player.PCStyle2.iPayzoneFlag;
|
||||
result.PlayerID = player.PCStyle.iPC_UID;
|
||||
result.SkinColor = player.PCStyle.iSkinColor;
|
||||
result.slot = player.slot;
|
||||
//taros
|
||||
result.TutorialFlag = player.PCStyle2.iTutorialFlag;
|
||||
result.x_coordinates = player.x;
|
||||
result.y_coordinates = player.y;
|
||||
result.z_coordinates = player.z;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Player Database::DbToPlayer(DbPlayer player) {
|
||||
Player result = {}; // fixes some weird memory errors, this zeros out the members (not the padding inbetween though)
|
||||
|
||||
result.accountId = player.AccountID;
|
||||
result.PCStyle2.iAppearanceFlag = player.AppearanceFlag;
|
||||
result.PCStyle.iBody = player.Body;
|
||||
result.PCStyle.iClass = player.Class;
|
||||
result.PCStyle.iEyeColor = player.EyeColor;
|
||||
result.PCStyle.iFaceStyle = player.FaceStyle;
|
||||
U8toU16(player.FirstName, result.PCStyle.szFirstName);
|
||||
result.PCStyle.iGender = player.Gender;
|
||||
result.PCStyle.iHairColor = player.HairColor;
|
||||
result.PCStyle.iHairStyle = player.HairStyle;
|
||||
result.PCStyle.iHeight = player.Height;
|
||||
result.HP = player.HP;
|
||||
result.IsGM = player.isGM;
|
||||
U8toU16(player.LastName, result.PCStyle.szLastName);
|
||||
result.level = player.Level;
|
||||
result.PCStyle.iNameCheck = player.NameCheck;
|
||||
result.PCStyle2.iPayzoneFlag = player.PayZoneFlag;
|
||||
result.iID = player.PlayerID;
|
||||
result.PCStyle.iPC_UID = player.PlayerID;
|
||||
result.PCStyle.iSkinColor = player.SkinColor;
|
||||
result.slot = player.slot;
|
||||
result.PCStyle2.iTutorialFlag = player.TutorialFlag;
|
||||
result.x = player.x_coordinates;
|
||||
result.y = player.y_coordinates;
|
||||
result.z = player.z_coordinates;
|
||||
|
||||
//TODO:: implement all of below
|
||||
result.SerialKey = 0;
|
||||
result.money = 0;
|
||||
result.fusionmatter = 0;
|
||||
result.activeNano = 0;
|
||||
result.iPCState = 0;
|
||||
result.equippedNanos[0] = 1;
|
||||
result.equippedNanos[1] = 0;
|
||||
result.equippedNanos[2] = 0;
|
||||
result.isTrading = false;
|
||||
result.isTradeConfirm = false;
|
||||
|
||||
result.Nanos[1].iID = 1;
|
||||
result.Nanos[1].iSkillID = 1;
|
||||
result.Nanos[1].iStamina = 150;
|
||||
|
||||
for (int i = 0; i < 37; i++) {
|
||||
result.Nanos[i].iID = 0;
|
||||
result.Nanos[i].iSkillID = 0;
|
||||
result.Nanos[i].iStamina = 0;
|
||||
}
|
||||
|
||||
result.Equip[0].iID = player.EquipWeapon1;
|
||||
result.Equip[0].iType = 0;
|
||||
(player.EquipWeapon1) ? result.Equip[0].iOpt = 1 : result.Equip[0].iOpt = 0;
|
||||
|
||||
result.Equip[1].iID = player.EquipUB;
|
||||
result.Equip[1].iType = 1;
|
||||
(player.EquipUB) ? result.Equip[1].iOpt = 1 : result.Equip[1].iOpt = 0;
|
||||
|
||||
result.Equip[2].iID = player.EquipLB;
|
||||
result.Equip[2].iType = 2;
|
||||
(player.EquipLB) ? result.Equip[2].iOpt = 1 : result.Equip[2].iOpt = 0;
|
||||
|
||||
result.Equip[3].iID = player.EquipFoot;
|
||||
result.Equip[3].iType = 3;
|
||||
(player.EquipFoot) ? result.Equip[3].iOpt = 1 : result.Equip[3].iOpt = 0;
|
||||
|
||||
|
||||
|
||||
for (int i = 4; i < AEQUIP_COUNT; i++) {
|
||||
// empty equips
|
||||
result.Equip[i].iID = 0;
|
||||
result.Equip[i].iType = i;
|
||||
result.Equip[i].iOpt = 0;
|
||||
}
|
||||
for (int i = 0; i < AINVEN_COUNT; i++) {
|
||||
// setup inventories
|
||||
result.Inven[i].iID = 0;
|
||||
result.Inven[i].iType = 0;
|
||||
result.Inven[i].iOpt = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Database::DbPlayer Database::getDbPlayerById(int id) {
|
||||
return db.get_all<DbPlayer>(where(c(&DbPlayer::PlayerID) == id))
|
||||
.front();
|
||||
}
|
||||
|
||||
#pragma endregion LoginServer
|
91
src/Database.hpp
Normal file
91
src/Database.hpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
#include "CNStructs.hpp"
|
||||
#include "Player.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Database {
|
||||
#pragma region DatabaseStructs
|
||||
|
||||
struct Account
|
||||
{
|
||||
int AccountID;
|
||||
std::string Login;
|
||||
std::string Password;
|
||||
int Selected;
|
||||
};
|
||||
struct Inventory
|
||||
{
|
||||
int AccountID;
|
||||
};
|
||||
struct DbPlayer
|
||||
{
|
||||
int PlayerID;
|
||||
int AccountID;
|
||||
short int slot;
|
||||
std::string FirstName;
|
||||
std::string LastName;
|
||||
short int AppearanceFlag;
|
||||
short int Body;
|
||||
short int Class;
|
||||
short int EquipFoot;
|
||||
short int EquipLB;
|
||||
short int EquipUB;
|
||||
short int EquipWeapon1;
|
||||
short int EquipWeapon2;
|
||||
short int EyeColor;
|
||||
short int FaceStyle;
|
||||
short int Gender;
|
||||
int HP;
|
||||
short int HairColor;
|
||||
short int HairStyle;
|
||||
short int Height;
|
||||
short int Level;
|
||||
short int NameCheck;
|
||||
short int PayZoneFlag;
|
||||
short int SkinColor;
|
||||
bool TutorialFlag;
|
||||
bool isGM;
|
||||
int FusionMatter;
|
||||
int Taros;
|
||||
int x_coordinates;
|
||||
int y_coordinates;
|
||||
int z_coordinates;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#pragma endregion DatabaseStructs
|
||||
|
||||
//handles migrations
|
||||
void open();
|
||||
//returns ID
|
||||
int addAccount(std::string login, std::string password);
|
||||
void updateSelected(int accountId, int playerId);
|
||||
std::unique_ptr<Account> findAccount(std::string login);
|
||||
bool isNameFree(sP_CL2LS_REQ_CHECK_CHAR_NAME* nameCheck);
|
||||
//called after chosing name, returns ID
|
||||
int createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID);
|
||||
//called after finishing creation
|
||||
void finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character);
|
||||
//called after tutorial
|
||||
void finishTutorial(int PlayerID);
|
||||
//returns slot number
|
||||
int deleteCharacter(int characterID);
|
||||
std::vector <Player> getCharacters(int userID);
|
||||
//accepting/declining custom name
|
||||
enum class CUSTOMNAME {
|
||||
approve = 1,
|
||||
disapprove = 2
|
||||
};
|
||||
void evaluateCustomName(int characterID, CUSTOMNAME decision);
|
||||
void changeName(sP_CL2LS_REQ_CHANGE_CHAR_NAME* save);
|
||||
|
||||
//parsing DbPlayer
|
||||
DbPlayer playerToDb(Player player);
|
||||
Player DbToPlayer(DbPlayer player);
|
||||
|
||||
//getting players
|
||||
DbPlayer getDbPlayerById(int id);
|
||||
|
||||
}
|
220
src/Defines.cpp
Normal file
220
src/Defines.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
#include <string>
|
||||
|
||||
#include "Defines.hpp"
|
||||
|
||||
#define STRINGIFY(x) PacketMap(x, #x)
|
||||
|
||||
/*
|
||||
* Turns out there isn't better way to do this...
|
||||
* We'll only support CL2* packets for now, since we only
|
||||
* need to print those.
|
||||
*/
|
||||
struct PacketMap {
|
||||
int val;
|
||||
std::string name;
|
||||
|
||||
PacketMap(int v, std::string n) : val(v), name(n) {};
|
||||
};
|
||||
|
||||
PacketMap cl2ls_map[] = {
|
||||
STRINGIFY(P_CL2LS_REQ_LOGIN),
|
||||
STRINGIFY(P_CL2LS_REQ_CHECK_CHAR_NAME),
|
||||
STRINGIFY(P_CL2LS_REQ_SAVE_CHAR_NAME),
|
||||
STRINGIFY(P_CL2LS_REQ_CHAR_CREATE),
|
||||
STRINGIFY(P_CL2LS_REQ_CHAR_SELECT),
|
||||
STRINGIFY(P_CL2LS_REQ_CHAR_DELETE),
|
||||
STRINGIFY(P_CL2LS_REQ_SHARD_SELECT),
|
||||
STRINGIFY(P_CL2LS_REQ_SHARD_LIST_INFO),
|
||||
STRINGIFY(P_CL2LS_CHECK_NAME_LIST),
|
||||
STRINGIFY(P_CL2LS_REQ_SAVE_CHAR_TUTOR),
|
||||
STRINGIFY(P_CL2LS_REQ_PC_EXIT_DUPLICATE),
|
||||
STRINGIFY(P_CL2LS_REP_LIVE_CHECK),
|
||||
STRINGIFY(P_CL2LS_REQ_CHANGE_CHAR_NAME),
|
||||
STRINGIFY(P_CL2LS_REQ_SERVER_SELECT),
|
||||
};
|
||||
|
||||
PacketMap cl2fe_map[] = {
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ENTER),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_EXIT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_MOVE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_STOP),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_JUMP),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ATTACK_NPCs),
|
||||
STRINGIFY(P_CL2FE_REQ_SEND_FREECHAT_MESSAGE),
|
||||
STRINGIFY(P_CL2FE_REQ_SEND_MENUCHAT_MESSAGE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_REGEN),
|
||||
STRINGIFY(P_CL2FE_REQ_ITEM_MOVE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TASK_START),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TASK_END),
|
||||
STRINGIFY(P_CL2FE_REQ_NANO_EQUIP),
|
||||
STRINGIFY(P_CL2FE_REQ_NANO_UNEQUIP),
|
||||
STRINGIFY(P_CL2FE_REQ_NANO_ACTIVE),
|
||||
STRINGIFY(P_CL2FE_REQ_NANO_TUNE),
|
||||
STRINGIFY(P_CL2FE_REQ_NANO_SKILL_USE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TASK_STOP),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TASK_CONTINUE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GOTO),
|
||||
STRINGIFY(P_CL2FE_REQ_CHARGE_NANO_STAMINA),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_KILL_QUEST_NPCs),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_VENDOR_ITEM_BUY),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_VENDOR_ITEM_SELL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ITEM_DELETE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GIVE_ITEM),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ROCKET_STYLE_READY),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ROCKET_STYLE_FIRE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ROCKET_STYLE_HIT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GRENADE_STYLE_READY),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GRENADE_STYLE_FIRE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GRENADE_STYLE_HIT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_NANO_CREATE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_OFFER),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_OFFER_CANCEL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_OFFER_ABORT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_CONFIRM),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_CONFIRM_ABORT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_CASH_REGISTER),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_BANK_OPEN),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_BANK_CLOSE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_VENDOR_START),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_VENDOR_TABLE_UPDATE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_VENDOR_ITEM_RESTORE_BUY),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_COMBAT_BEGIN),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_COMBAT_END),
|
||||
STRINGIFY(P_CL2FE_REQ_REQUEST_MAKE_BUDDY),
|
||||
STRINGIFY(P_CL2FE_REQ_ACCEPT_MAKE_BUDDY),
|
||||
STRINGIFY(P_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE),
|
||||
STRINGIFY(P_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE),
|
||||
STRINGIFY(P_CL2FE_REQ_GET_BUDDY_STYLE),
|
||||
STRINGIFY(P_CL2FE_REQ_SET_BUDDY_BLOCK),
|
||||
STRINGIFY(P_CL2FE_REQ_REMOVE_BUDDY),
|
||||
STRINGIFY(P_CL2FE_REQ_GET_BUDDY_STATE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_JUMPPAD),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_LAUNCHER),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ZIPLINE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_MOVEPLATFORM),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_SLOPE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_STATE_CHANGE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_MAP_WARP),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GIVE_NANO),
|
||||
STRINGIFY(P_CL2FE_REQ_NPC_SUMMON),
|
||||
STRINGIFY(P_CL2FE_REQ_NPC_UNSUMMON),
|
||||
STRINGIFY(P_CL2FE_REQ_ITEM_CHEST_OPEN),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GIVE_NANO_SKILL),
|
||||
STRINGIFY(P_CL2FE_DOT_DAMAGE_ONOFF),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_VENDOR_BATTERY_BUY),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_WARP_USE_NPC),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GROUP_INVITE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GROUP_JOIN),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_GROUP_LEAVE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_BUDDY_WARP),
|
||||
STRINGIFY(P_CL2FE_REQ_GET_MEMBER_STYLE),
|
||||
STRINGIFY(P_CL2FE_REQ_GET_GROUP_STYLE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_CHANGE_MENTOR),
|
||||
STRINGIFY(P_CL2FE_REQ_GET_BUDDY_LOCATION),
|
||||
STRINGIFY(P_CL2FE_REQ_NPC_GROUP_SUMMON),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_WARP_TO_PC),
|
||||
STRINGIFY(P_CL2FE_REQ_EP_RANK_GET_LIST),
|
||||
STRINGIFY(P_CL2FE_REQ_EP_RANK_GET_DETAIL),
|
||||
STRINGIFY(P_CL2FE_REQ_EP_RANK_GET_PC_INFO),
|
||||
STRINGIFY(P_CL2FE_REQ_EP_RACE_START),
|
||||
STRINGIFY(P_CL2FE_REQ_EP_RACE_END),
|
||||
STRINGIFY(P_CL2FE_REQ_EP_RACE_CANCEL),
|
||||
STRINGIFY(P_CL2FE_REQ_EP_GET_RING),
|
||||
STRINGIFY(P_CL2FE_REQ_IM_CHANGE_SWITCH_STATUS),
|
||||
STRINGIFY(P_CL2FE_REQ_SHINY_PICKUP),
|
||||
STRINGIFY(P_CL2FE_REQ_SHINY_SUMMON),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_MOVETRANSPORTATION),
|
||||
STRINGIFY(P_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE),
|
||||
STRINGIFY(P_CL2FE_REQ_SEND_ANY_GROUP_FREECHAT_MESSAGE),
|
||||
STRINGIFY(P_CL2FE_REQ_BARKER),
|
||||
STRINGIFY(P_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE),
|
||||
STRINGIFY(P_CL2FE_REQ_SEND_ANY_GROUP_MENUCHAT_MESSAGE),
|
||||
STRINGIFY(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_PC_SET_VALUE),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_KICK_PLAYER),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_TARGET_PC_TELEPORT),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_PC_LOCATION),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_PC_ANNOUNCE),
|
||||
STRINGIFY(P_CL2FE_REQ_SET_PC_BLOCK),
|
||||
STRINGIFY(P_CL2FE_REQ_REGIST_RXCOM),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_PC_MOTD_REGISTER),
|
||||
STRINGIFY(P_CL2FE_REQ_ITEM_USE),
|
||||
STRINGIFY(P_CL2FE_REQ_WARP_USE_RECALL),
|
||||
STRINGIFY(P_CL2FE_REP_LIVE_CHECK),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_MISSION_COMPLETE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TASK_COMPLETE),
|
||||
STRINGIFY(P_CL2FE_REQ_NPC_INTERACTION),
|
||||
STRINGIFY(P_CL2FE_DOT_HEAL_ONOFF),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_EMAIL_UPDATE_CHECK),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_READ_EMAIL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_RECV_EMAIL_PAGE_LIST),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_DELETE_EMAIL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_SEND_EMAIL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_RECV_EMAIL_ITEM),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_RECV_EMAIL_CANDY),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID),
|
||||
STRINGIFY(P_CL2FE_REQ_NPC_GROUP_INVITE),
|
||||
STRINGIFY(P_CL2FE_REQ_NPC_GROUP_KICK),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_FIRST_USE_FLAG_SET),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TRANSPORT_WARP),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_TIME_TO_GO_WARP),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_RECV_EMAIL_ITEM_ALL),
|
||||
STRINGIFY(P_CL2FE_REQ_CHANNEL_INFO),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_CHANNEL_NUM),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_WARP_CHANNEL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_LOADING_COMPLETE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_FIND_NAME_MAKE_BUDDY),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_FIND_NAME_ACCEPT_BUDDY),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ATTACK_CHARs),
|
||||
STRINGIFY(P_CL2FE_PC_STREETSTALL_REQ_READY),
|
||||
STRINGIFY(P_CL2FE_PC_STREETSTALL_REQ_CANCEL),
|
||||
STRINGIFY(P_CL2FE_PC_STREETSTALL_REQ_REGIST_ITEM),
|
||||
STRINGIFY(P_CL2FE_PC_STREETSTALL_REQ_UNREGIST_ITEM),
|
||||
STRINGIFY(P_CL2FE_PC_STREETSTALL_REQ_SALE_START),
|
||||
STRINGIFY(P_CL2FE_PC_STREETSTALL_REQ_ITEM_LIST),
|
||||
STRINGIFY(P_CL2FE_PC_STREETSTALL_REQ_ITEM_BUY),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ITEM_COMBINATION),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_SET_PC_SKILL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_SKILL_ADD),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_SKILL_DEL),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_SKILL_USE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ROPE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_BELT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_VEHICLE_ON),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_VEHICLE_OFF),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_REGIST_QUICK_SLOT),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_DISASSEMBLE_ITEM),
|
||||
STRINGIFY(P_CL2FE_GM_REQ_REWARD_RATE),
|
||||
STRINGIFY(P_CL2FE_REQ_PC_ITEM_ENCHANT),
|
||||
};
|
||||
|
||||
std::string Defines::p2str(int type, int val) {
|
||||
switch (type) {
|
||||
case CL2LS:
|
||||
val = val - CL2LS - 1;
|
||||
if (val > N_CL2LS || val < 0)
|
||||
break;
|
||||
|
||||
return cl2ls_map[val].name;
|
||||
case CL2FE:
|
||||
val = val - CL2FE - 1;
|
||||
if (val > N_CL2FE || val < 0)
|
||||
break;
|
||||
|
||||
return cl2fe_map[val].name;
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
857
src/Defines.hpp
Normal file
857
src/Defines.hpp
Normal file
@@ -0,0 +1,857 @@
|
||||
/* enum definitions from the client */
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* TODO: It might be a good idea to make this file build-specific, but
|
||||
* I'm pretty sure there were seldom any new packets added, and they're
|
||||
* probably always going to be the non-essential things that we won't be
|
||||
* implementing just yet anyway.
|
||||
*/
|
||||
|
||||
const float VALUE_BATTERY_EMPTY_PENALTY = 0.5f;
|
||||
const float CN_EP_RANK_1 = 0.8f;
|
||||
const float CN_EP_RANK_2 = 0.7f;
|
||||
const float CN_EP_RANK_3 = 0.5f;
|
||||
const float CN_EP_RANK_4 = 0.3f;
|
||||
const float CN_EP_RANK_5 = 0.29f;
|
||||
|
||||
enum {
|
||||
SUCC = 1,
|
||||
FAIL = 0,
|
||||
|
||||
SIZEOF_BYTE = 1,
|
||||
SIZEOF_DWORD = 4,
|
||||
SIZEOF_INT = 4,
|
||||
SIZEOF_FLOAT = 4,
|
||||
SIZEOF_SHORT = 2,
|
||||
SIZEOF_ULONG = 4,
|
||||
SIZEOF_UINT64 = 8,
|
||||
SIZEOF_IP_STRING = 16,
|
||||
SIZEOF_CN_UID_STRING = 50,
|
||||
SIZEOF_ACCOUNT_STRING = 33,
|
||||
SIZEOF_PASSWORD_STRING = 33,
|
||||
SIZEOF_AUTH_ID_STRING = 255,
|
||||
|
||||
CN_MAX_COUNT_GROUP_MEMBER = 5,
|
||||
CN_MAX_COUNT_PC_GROUP_MEMBER = 4,
|
||||
CN_MAX_COUNT_NPC_GROUP_MEMBER = 5,
|
||||
|
||||
CHAT_MAX_STRING = 128,
|
||||
PC_START_LOCATION_RANDOM_RANGE = 10000,
|
||||
SIZEOF_ANNOUNCE_STRING = 512,
|
||||
SERVER_COUNT_SHARD_CLIENT = 25,
|
||||
|
||||
EXIT_CODE_DISCONNECT = 0,
|
||||
EXIT_CODE_REQ_BY_PC = 1,
|
||||
EXIT_CODE_REQ_BY_SVR = 2,
|
||||
EXIT_CODE_REQ_BY_GM = 3,
|
||||
EXIT_CODE_HACK = 4,
|
||||
EXIT_CODE_ERROR = 5,
|
||||
EXIT_CODE_LIVE_CHECK = 6,
|
||||
EXIT_CODE_REQ_BY_PC_DUPE_LOGIN = 7,
|
||||
EXIT_CODE_SERVER_ERROR = 99,
|
||||
|
||||
SIZEOF_USER_ID = 32,
|
||||
SIZEOF_USER_PW = 32,
|
||||
SIZEOF_PC_SLOT = 4,
|
||||
SIZEOF_PC_NAME = 16,
|
||||
SIZEOF_PC_FIRST_NAME = 9,
|
||||
SIZEOF_PC_LAST_NAME = 17,
|
||||
SIZEOF_PC_NAME_FLAG = 8,
|
||||
|
||||
GENDER_NONE = 0,
|
||||
GENDER_MALE = 1,
|
||||
GENDER_FEMALE = 2,
|
||||
|
||||
MENTOR_CHANGE_BASE_COST = 100,
|
||||
REPEAT_MISSION_RESET_TIME = 9,
|
||||
SIZEOF_REPEAT_QUESTFLAG_NUMBER = 8,
|
||||
FATIGUE_RESET_TIME = 0,
|
||||
|
||||
PC_FATIGUE_KILL_UNIT = 7,
|
||||
PC_FATIGUE_1_LEVEL = 11420,
|
||||
PC_FATIGUE_2_LEVEL = 6480,
|
||||
PC_FATIGUE_MAX_LEVEL = 2,
|
||||
PC_FUSIONMATTER_MAX = 999999999,
|
||||
PC_CANDY_MAX = 999999999,
|
||||
PC_BATTERY_MAX = 9999,
|
||||
PC_LEVEL_MAX = 36,
|
||||
SIZEOF_PC_BULLET_SLOT = 3,
|
||||
PC_TICK_TIME = 5000,
|
||||
SIZEOF_EQUIP_SLOT = 9,
|
||||
|
||||
EQUIP_SLOT_HAND = 0,
|
||||
EQUIP_SLOT_UPPERBODY = 1,
|
||||
EQUIP_SLOT_LOWERBODY = 2,
|
||||
EQUIP_SLOT_FOOT = 3,
|
||||
EQUIP_SLOT_HEAD = 4,
|
||||
EQUIP_SLOT_FACE = 5,
|
||||
EQUIP_SLOT_BACK = 6,
|
||||
EQUIP_SLOT_END = 6,
|
||||
EQUIP_SLOT_HAND_EX = 7,
|
||||
EQUIP_SLOT_VEHICLE = 8,
|
||||
|
||||
WPN_EQUIP_TYPE_NONE = 0,
|
||||
WPN_EQUIP_TYPE_OH_BLADE = 1,
|
||||
WPN_EQUIP_TYPE_OH_CLUB = 2,
|
||||
WPN_EQUIP_TYPE_OH_PISTOL = 3,
|
||||
WPN_EQUIP_TYPE_OH_RIPLE = 4,
|
||||
WPN_EQUIP_TYPE_OH_THROW = 5,
|
||||
WPN_EQUIP_TYPE_DH_BLADE = 6,
|
||||
WPN_EQUIP_TYPE_DH_CLUB = 7,
|
||||
WPN_EQUIP_TYPE_DH_DPISTOL = 8,
|
||||
WPN_EQUIP_TYPE_DH_RIPLE = 9,
|
||||
WPN_EQUIP_TYPE_DH_THROW = 10,
|
||||
WPN_EQUIP_TYPE_DH_ROCKET = 11,
|
||||
|
||||
SIZEOF_INVEN_SLOT = 50,
|
||||
SIZEOF_QINVEN_SLOT = 50,
|
||||
SIZEOF_BANK_SLOT = 119,
|
||||
SIZEOF_RESTORE_SLOT = 5,
|
||||
SIZEOF_NANO_BANK_SLOT = 37,
|
||||
SIZEOF_QUEST_SLOT = 1024,
|
||||
NANO_QUEST_INDEX = 0,
|
||||
SIZEOF_RQUEST_SLOT = 9,
|
||||
SIZEOF_QUESTFLAG_NUMBER = 32,
|
||||
SIZEOF_EP_RECORD_SLOT = 51,
|
||||
SIZEOF_TRADE_SLOT = 12,
|
||||
SIZEOF_VENDOR_TABLE_SLOT = 20,
|
||||
SIZEOF_VENDOR_RESTORE_SLOT = 5,
|
||||
SIZEOF_QUEST_NPC_SLOT = 3,
|
||||
SIZEOF_QUEST_ITEM_SLOT = 3,
|
||||
SIZEOF_MAX_ITEM_STACK = 100,
|
||||
SIZEOF_PC_SKILL_SLOT = 33,
|
||||
SIZEOF_QUICK_SLOT = 8,
|
||||
ENCHANT_WEAPON_MATERIAL_ID = 101,
|
||||
ENCHANT_DEFENCE_MATERIAL_ID = 102,
|
||||
SIZEOF_NANO_CARRY_SLOT = 3,
|
||||
COUNTOF_NANO_PER_SET = 3,
|
||||
SIZEOF_NANO_SET = 13,
|
||||
SIZEOF_NANO_STYLE = 3,
|
||||
NANO_STYLE_NONE = 1,
|
||||
NANO_STYLE_CRYSTAL = 0,
|
||||
NANO_STYLE_ENERGY = 1,
|
||||
NANO_STYLE_FLUID = 2,
|
||||
SIZEOF_NANO_TYPE = 4,
|
||||
NANO_TYPE_POWER = 0,
|
||||
NANO_TYPE_ACCURACY = 1,
|
||||
NANO_TYPE_PROTECT = 2,
|
||||
NANO_TYPE_DODGE = 3,
|
||||
SIZEOF_NANO_TUNE_NEED_ITEM_SLOT = 10,
|
||||
VALUE_ATTACK_MISS = 1,
|
||||
|
||||
MSG_ONLINE = 1,
|
||||
MSG_BUSY = 2,
|
||||
MSG_OFFLINE = 0,
|
||||
SIZEOF_FREE_CHAT_STRING = 128,
|
||||
SIZEOF_MENU_CHAT_STRING = 128,
|
||||
SIZEOF_BUDDYLIST_SLOT = 50,
|
||||
SIZEOF_EMAIL_SUBJECT_STRING = 32,
|
||||
SIZEOF_EMAIL_CONTENT_STRING = 512,
|
||||
SIZEOF_EMAIL_PAGE_SIZE = 5,
|
||||
SIZEOF_EMAIL_ITEM_CNT = 4,
|
||||
EMAIL_AND_MONEY_COST = 50,
|
||||
EMAIL_ITEM_COST = 20,
|
||||
BUDDYWARP_INTERVAL = 60,
|
||||
EMAILSEND_TIME_DELAY = 60,
|
||||
DB_ERROR_INVALID_DATA = 1,
|
||||
DB_ERROR_HACK_ATTEMPT = 2,
|
||||
DB_ERROR_ACCESS_FAIL = 3,
|
||||
DB_ERROR_PC_INSERT_FAIL = 4,
|
||||
CALL_NPC_MAX_CNT = 2048,
|
||||
|
||||
CN_EP_RING_MAX_CNT = 999,
|
||||
|
||||
HF_BIT_NONE = 0,
|
||||
HF_BIT_NORMAL = 1,
|
||||
HF_BIT_CRITICAL = 2,
|
||||
HF_BIT_STYLE_WIN = 4,
|
||||
HF_BIT_STYLE_TIE = 8,
|
||||
HF_BIT_STYLE_LOSE = 16,
|
||||
SKIN_COLOR_MAX = 12,
|
||||
HAIR_COLOR_MAX = 18,
|
||||
EYE_COLOR_MAX = 5,
|
||||
BODY_TYPE_MAX = 3,
|
||||
HEIGHT_TYPE_MAX = 5,
|
||||
CLASS_TYPE_MAX = 4,
|
||||
CN_EP_RACE_MODE_PRACTICE = 0,
|
||||
CN_EP_RACE_MODE_RECORD = 1,
|
||||
CN_EP_SECOM_NPC_TYPE_NUM = 13,
|
||||
CN_EP_EECOM_NPC_TYPE_NUM = 14,
|
||||
CN_EP_SIZE_SMALL = 0,
|
||||
CN_EP_SIZE_MIDDLE = 1,
|
||||
CN_EP_SIZE_BIG = 2,
|
||||
CN_EP_TICKET_ITEM_ID_SMALL = 115,
|
||||
CN_EP_TICKET_ITEM_ID_MIDDLE = 116,
|
||||
CN_EP_TICKET_ITEM_ID_BIG = 117,
|
||||
CN_EP_TICKET_ITEM_ID_FREE = 118,
|
||||
CN_EP_DISTANCE_ERROR_SAFE_RANGE = 1200,
|
||||
|
||||
CN_ACCOUNT_LEVEL__MASTER = 1,
|
||||
CN_ACCOUNT_LEVEL__POWER_DEVELOPER = 10,
|
||||
CN_ACCOUNT_LEVEL__QA = 20,
|
||||
CN_ACCOUNT_LEVEL__GM = 30,
|
||||
CN_ACCOUNT_LEVEL__CS = 40,
|
||||
CN_ACCOUNT_LEVEL__FREE_USER = 48,
|
||||
CN_ACCOUNT_LEVEL__PAY_USER = 49,
|
||||
CN_ACCOUNT_LEVEL__DEVELOPER = 50,
|
||||
CN_ACCOUNT_LEVEL__CLOSEBETA_USER = 80,
|
||||
CN_ACCOUNT_LEVEL__OPENBETA_USER = 85,
|
||||
CN_ACCOUNT_LEVEL__USER = 99,
|
||||
|
||||
CN_SPECIAL_STATE_FLAG__PRINT_GM = 1,
|
||||
CN_SPECIAL_STATE_FLAG__INVISIBLE = 2,
|
||||
CN_SPECIAL_STATE_FLAG__INVULNERABLE = 4,
|
||||
CN_SPECIAL_STATE_FLAG__FULL_UI = 16,
|
||||
CN_SPECIAL_STATE_FLAG__COMBAT = 32,
|
||||
CN_SPECIAL_STATE_FLAG__MUTE_FREECHAT = 64,
|
||||
|
||||
CN_GM_SET_VALUE_TYPE__HP = 1,
|
||||
CN_GM_SET_VALUE_TYPE__WEAPON_BATTERY = 2,
|
||||
CN_GM_SET_VALUE_TYPE__NANO_BATTERY = 3,
|
||||
CN_GM_SET_VALUE_TYPE__FUSION_MATTER = 4,
|
||||
CN_GM_SET_VALUE_TYPE__CANDY = 5,
|
||||
CN_GM_SET_VALUE_TYPE__SPEED = 6,
|
||||
CN_GM_SET_VALUE_TYPE__JUMP = 7,
|
||||
CN_GM_SET_VALUE_TYPE__END = 8,
|
||||
|
||||
HEIGHT_CLIMBABLE = 150,
|
||||
CN_GROUP_WARP_CHECK_RANGE = 1000,
|
||||
WYVERN_LOCATION_FLAG_SIZE = 2,
|
||||
CN_PC_EVENT_ID_GET_NANO_QUEST = 1,
|
||||
CN_PC_EVENT_ID_DEFEAT_FUSE_AND_GET_NANO = 2,
|
||||
_dCN_STREETSTALL__ITEMLIST_COUNT_MAX = 5,
|
||||
|
||||
CSB_BIT_NONE = 0, // 0
|
||||
CSB_BIT_UP_MOVE_SPEED = 0x1, // 1
|
||||
CSB_BIT_UP_SWIM_SPEED = 0x2, // 2
|
||||
CSB_BIT_UP_JUMP_HEIGHT = 0x4, // 4
|
||||
CSB_BIT_UP_STEALTH = 0x8, // 8
|
||||
CSB_BIT_PHOENIX = 0x10, // 16
|
||||
CSB_BIT_PROTECT_BATTERY = 0x20, // 32
|
||||
CSB_BIT_PROTECT_INFECTION = 0x40, // 64
|
||||
CSB_BIT_DN_MOVE_SPEED = 0x80, // 128
|
||||
CSB_BIT_DN_ATTACK_SPEED = 0x100, // 256
|
||||
CSB_BIT_STUN = 0x200, // 512
|
||||
CSB_BIT_MEZ = 0x400, // 1024
|
||||
CSB_BIT_KNOCKDOWN = 0x800, // 2048
|
||||
CSB_BIT_MINIMAP_ENEMY = 0x1000, // 4096
|
||||
CSB_BIT_MINIMAP_TRESURE = 0x2000, // 8192
|
||||
CSB_BIT_REWARD_BLOB = 0x4000, // 16384
|
||||
CSB_BIT_REWARD_CASH = 0x8000, // 32768
|
||||
CSB_BIT_INFECTION = 0x10000, // 65536
|
||||
CSB_BIT_FREEDOM = 0x20000, // 131072
|
||||
CSB_BIT_BOUNDINGBALL = 0x40000, // 262144
|
||||
CSB_BIT_INVULNERABLE = 0x80000, // 524288
|
||||
CSB_BIT_STIMPAKSLOT1 = 0x100000, // 1048576
|
||||
CSB_BIT_STIMPAKSLOT2 = 0x200000, // 2097152
|
||||
CSB_BIT_STIMPAKSLOT3 = 0x400000, // 4194304
|
||||
CSB_BIT_HEAL = 0x800000, // 8388608
|
||||
CSB_BIT_EXTRABANK = 0x1000000, // 16777216
|
||||
|
||||
TIME_BUFF_CONFIRM_KEY_MAX = 2000000000,
|
||||
READPACKET_SUCC = 0,
|
||||
READPACKET_FAIL = 1,
|
||||
READPACKET_RETURN = 2,
|
||||
BITMASK_FROM2TO = 0x7fffffff, // 2147483647
|
||||
BITMASK_FROM = 0x7fffffff, // 2147483647
|
||||
BITMASK_TO = 0xf000000, // 251658240
|
||||
BITMASK_SENDBLOCK = 0x800000, // 8388608
|
||||
BITMASK_AUTHED = 0x400000, // 4194304
|
||||
BITMASK_U_ID = 0xfff, // 4095
|
||||
|
||||
CL2LS = 0x12000000,
|
||||
CL2FE = 0x13000000,
|
||||
LS2CL = 0x21000000,
|
||||
LS2LS = 0x22000000,
|
||||
LS2DBA = 0x27000000,
|
||||
FE2CL = 0x31000000,
|
||||
FE2FE = 0x33000000,
|
||||
FE2GS = 0x34000000,
|
||||
FE2EP = 0x36000000,
|
||||
FE2MSG = 0x38000000,
|
||||
GS2FE = 0x43000000,
|
||||
GS2GS = 0x44000000,
|
||||
GS2AI = 0x45000000,
|
||||
GS2EP = 0x46000000,
|
||||
GS2DBA = 0x47000000,
|
||||
GS2MSG = 0x48000000,
|
||||
GS2MGR = 0x4a000000,
|
||||
AI2GS = 0x54000000,
|
||||
EP2FE = 0x63000000,
|
||||
EP2GS = 0x64000000,
|
||||
DBA2GS = 0x74000000,
|
||||
DBA2EP = 0x75000000,
|
||||
MSG2FE = 0x7fffffff,
|
||||
MSG2GS = 0x7fffffff,
|
||||
MSG2CMSG = 0x7fffffff,
|
||||
CMSG2MSG = 0x7fffffff,
|
||||
MGR2SPY = 0x7fffffff,
|
||||
SPY2MGR = 0x7fffffff,
|
||||
MGR2SA = 0x7fffffff,
|
||||
SA2MGR = 0x7fffffff,
|
||||
SA2SPY = 0x7fffffff,
|
||||
SPY2SA = 0x7fffffff,
|
||||
SPY2SVR = 0x7fffffff,
|
||||
SVR2SPY = 0x7fffffff,
|
||||
SCH2SVR = 0x7fffffff,
|
||||
SCH2LS = 0x7fffffff,
|
||||
SCH2FE = 0x7fffffff,
|
||||
SCH2GS = 0x7fffffff,
|
||||
SCH2AI = 0x7fffffff,
|
||||
SCH2EP = 0x7fffffff,
|
||||
SCH2DBA = 0x7fffffff,
|
||||
SCH2MSG = 0x7fffffff,
|
||||
SCH2CMSG = 0x7fffffff,
|
||||
CL2CDR = 0x1f000000,
|
||||
|
||||
SENDBLOCK = 0x800000, // 8388608
|
||||
AUTHED_X = 0, // 0
|
||||
AUTHED_O = 0x400000, // 4194304
|
||||
|
||||
SEND_SVR_FE = 1,
|
||||
SEND_SVR_FE_ANY = 2,
|
||||
SEND_SVR_FE_ALL = 3,
|
||||
SEND_SVR_AI = 4,
|
||||
SEND_SVR_AI_ANY = 5,
|
||||
SEND_SVR_AI_ALL = 6,
|
||||
SEND_SVR_FE_AI_ALL = 7,
|
||||
SEND_SVR_DBA = 8,
|
||||
SEND_SVR_GS = 9,
|
||||
SEND_SVR_MSG = 10,
|
||||
SEND_SVR_MSG_ANY = 11,
|
||||
SEND_SVR_MSG_ALL = 12,
|
||||
|
||||
SEND_UNICAST = 1,
|
||||
SEND_ANYCAST = 2,
|
||||
SEND_ANYCAST_NEW = 3,
|
||||
SEND_BROADCAST = 4,
|
||||
|
||||
CN_PACKET_BUFFER_SIZE = 4096,
|
||||
|
||||
P_CL2LS_REQ_LOGIN = 0x12000001, // 301989889
|
||||
P_CL2LS_REQ_CHECK_CHAR_NAME = 0x12000002, // 301989890
|
||||
P_CL2LS_REQ_SAVE_CHAR_NAME = 0x12000003, // 301989891
|
||||
P_CL2LS_REQ_CHAR_CREATE = 0x12000004, // 301989892
|
||||
P_CL2LS_REQ_CHAR_SELECT = 0x12000005, // 301989893
|
||||
P_CL2LS_REQ_CHAR_DELETE = 0x12000006, // 301989894
|
||||
P_CL2LS_REQ_SHARD_SELECT = 0x12000007, // 301989895
|
||||
P_CL2LS_REQ_SHARD_LIST_INFO = 0x12000008, // 301989896
|
||||
P_CL2LS_CHECK_NAME_LIST = 0x12000009, // 301989897
|
||||
P_CL2LS_REQ_SAVE_CHAR_TUTOR = 0x1200000a, // 301989898
|
||||
P_CL2LS_REQ_PC_EXIT_DUPLICATE = 0x1200000b, // 301989899
|
||||
P_CL2LS_REP_LIVE_CHECK = 0x1200000c, // 301989900
|
||||
P_CL2LS_REQ_CHANGE_CHAR_NAME = 0x1200000d, // 301989901
|
||||
P_CL2LS_REQ_SERVER_SELECT = 0x1200000e, // 301989902
|
||||
|
||||
P_CL2FE_REQ_PC_ENTER = 0x13000001, // 318767105
|
||||
P_CL2FE_REQ_PC_EXIT = 0x13000002, // 318767106
|
||||
P_CL2FE_REQ_PC_MOVE = 0x13000003, // 318767107
|
||||
P_CL2FE_REQ_PC_STOP = 0x13000004, // 318767108
|
||||
P_CL2FE_REQ_PC_JUMP = 0x13000005, // 318767109
|
||||
P_CL2FE_REQ_PC_ATTACK_NPCs = 0x13000006, // 318767110
|
||||
P_CL2FE_REQ_SEND_FREECHAT_MESSAGE = 0x13000007, // 318767111
|
||||
P_CL2FE_REQ_SEND_MENUCHAT_MESSAGE = 0x13000008, // 318767112
|
||||
P_CL2FE_REQ_PC_REGEN = 0x13000009, // 318767113
|
||||
P_CL2FE_REQ_ITEM_MOVE = 0x1300000a, // 318767114
|
||||
P_CL2FE_REQ_PC_TASK_START = 0x1300000b, // 318767115
|
||||
P_CL2FE_REQ_PC_TASK_END = 0x1300000c, // 318767116
|
||||
P_CL2FE_REQ_NANO_EQUIP = 0x1300000d, // 318767117
|
||||
P_CL2FE_REQ_NANO_UNEQUIP = 0x1300000e, // 318767118
|
||||
P_CL2FE_REQ_NANO_ACTIVE = 0x1300000f, // 318767119
|
||||
P_CL2FE_REQ_NANO_TUNE = 0x13000010, // 318767120
|
||||
P_CL2FE_REQ_NANO_SKILL_USE = 0x13000011, // 318767121
|
||||
P_CL2FE_REQ_PC_TASK_STOP = 0x13000012, // 318767122
|
||||
P_CL2FE_REQ_PC_TASK_CONTINUE = 0x13000013, // 318767123
|
||||
P_CL2FE_REQ_PC_GOTO = 0x13000014, // 318767124
|
||||
P_CL2FE_REQ_CHARGE_NANO_STAMINA = 0x13000015, // 318767125
|
||||
P_CL2FE_REQ_PC_KILL_QUEST_NPCs = 0x13000016, // 318767126
|
||||
P_CL2FE_REQ_PC_VENDOR_ITEM_BUY = 0x13000017, // 318767127
|
||||
P_CL2FE_REQ_PC_VENDOR_ITEM_SELL = 0x13000018, // 318767128
|
||||
P_CL2FE_REQ_PC_ITEM_DELETE = 0x13000019, // 318767129
|
||||
P_CL2FE_REQ_PC_GIVE_ITEM = 0x1300001a, // 318767130
|
||||
P_CL2FE_REQ_PC_ROCKET_STYLE_READY = 0x1300001b, // 318767131
|
||||
P_CL2FE_REQ_PC_ROCKET_STYLE_FIRE = 0x1300001c, // 318767132
|
||||
P_CL2FE_REQ_PC_ROCKET_STYLE_HIT = 0x1300001d, // 318767133
|
||||
P_CL2FE_REQ_PC_GRENADE_STYLE_READY = 0x1300001e, // 318767134
|
||||
P_CL2FE_REQ_PC_GRENADE_STYLE_FIRE = 0x1300001f, // 318767135
|
||||
P_CL2FE_REQ_PC_GRENADE_STYLE_HIT = 0x13000020, // 318767136
|
||||
P_CL2FE_REQ_PC_NANO_CREATE = 0x13000021, // 318767137
|
||||
P_CL2FE_REQ_PC_TRADE_OFFER = 0x13000022, // 318767138
|
||||
P_CL2FE_REQ_PC_TRADE_OFFER_CANCEL = 0x13000023, // 318767139
|
||||
P_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT = 0x13000024, // 318767140
|
||||
P_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL = 0x13000025, // 318767141
|
||||
P_CL2FE_REQ_PC_TRADE_OFFER_ABORT = 0x13000026, // 318767142
|
||||
P_CL2FE_REQ_PC_TRADE_CONFIRM = 0x13000027, // 318767143
|
||||
P_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL = 0x13000028, // 318767144
|
||||
P_CL2FE_REQ_PC_TRADE_CONFIRM_ABORT = 0x13000029, // 318767145
|
||||
P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER = 0x1300002a, // 318767146
|
||||
P_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER = 0x1300002b, // 318767147
|
||||
P_CL2FE_REQ_PC_TRADE_CASH_REGISTER = 0x1300002c, // 318767148
|
||||
P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT = 0x1300002d, // 318767149
|
||||
P_CL2FE_REQ_PC_BANK_OPEN = 0x1300002e, // 318767150
|
||||
P_CL2FE_REQ_PC_BANK_CLOSE = 0x1300002f, // 318767151
|
||||
P_CL2FE_REQ_PC_VENDOR_START = 0x13000030, // 318767152
|
||||
P_CL2FE_REQ_PC_VENDOR_TABLE_UPDATE = 0x13000031, // 318767153
|
||||
P_CL2FE_REQ_PC_VENDOR_ITEM_RESTORE_BUY = 0x13000032, // 318767154
|
||||
P_CL2FE_REQ_PC_COMBAT_BEGIN = 0x13000033, // 318767155
|
||||
P_CL2FE_REQ_PC_COMBAT_END = 0x13000034, // 318767156
|
||||
P_CL2FE_REQ_REQUEST_MAKE_BUDDY = 0x13000035, // 318767157
|
||||
P_CL2FE_REQ_ACCEPT_MAKE_BUDDY = 0x13000036, // 318767158
|
||||
P_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE = 0x13000037, // 318767159
|
||||
P_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE = 0x13000038, // 318767160
|
||||
P_CL2FE_REQ_GET_BUDDY_STYLE = 0x13000039, // 318767161
|
||||
P_CL2FE_REQ_SET_BUDDY_BLOCK = 0x1300003a, // 318767162
|
||||
P_CL2FE_REQ_REMOVE_BUDDY = 0x1300003b, // 318767163
|
||||
P_CL2FE_REQ_GET_BUDDY_STATE = 0x1300003c, // 318767164
|
||||
P_CL2FE_REQ_PC_JUMPPAD = 0x1300003d, // 318767165
|
||||
P_CL2FE_REQ_PC_LAUNCHER = 0x1300003e, // 318767166
|
||||
P_CL2FE_REQ_PC_ZIPLINE = 0x1300003f, // 318767167
|
||||
P_CL2FE_REQ_PC_MOVEPLATFORM = 0x13000040, // 318767168
|
||||
P_CL2FE_REQ_PC_SLOPE = 0x13000041, // 318767169
|
||||
P_CL2FE_REQ_PC_STATE_CHANGE = 0x13000042, // 318767170
|
||||
P_CL2FE_REQ_PC_MAP_WARP = 0x13000043, // 318767171
|
||||
P_CL2FE_REQ_PC_GIVE_NANO = 0x13000044, // 318767172
|
||||
P_CL2FE_REQ_NPC_SUMMON = 0x13000045, // 318767173
|
||||
P_CL2FE_REQ_NPC_UNSUMMON = 0x13000046, // 318767174
|
||||
P_CL2FE_REQ_ITEM_CHEST_OPEN = 0x13000047, // 318767175
|
||||
P_CL2FE_REQ_PC_GIVE_NANO_SKILL = 0x13000048, // 318767176
|
||||
P_CL2FE_DOT_DAMAGE_ONOFF = 0x13000049, // 318767177
|
||||
P_CL2FE_REQ_PC_VENDOR_BATTERY_BUY = 0x1300004a, // 318767178
|
||||
P_CL2FE_REQ_PC_WARP_USE_NPC = 0x1300004b, // 318767179
|
||||
P_CL2FE_REQ_PC_GROUP_INVITE = 0x1300004c, // 318767180
|
||||
P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE = 0x1300004d, // 318767181
|
||||
P_CL2FE_REQ_PC_GROUP_JOIN = 0x1300004e, // 318767182
|
||||
P_CL2FE_REQ_PC_GROUP_LEAVE = 0x1300004f, // 318767183
|
||||
P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT = 0x13000050, // 318767184
|
||||
P_CL2FE_REQ_PC_BUDDY_WARP = 0x13000051, // 318767185
|
||||
P_CL2FE_REQ_GET_MEMBER_STYLE = 0x13000052, // 318767186
|
||||
P_CL2FE_REQ_GET_GROUP_STYLE = 0x13000053, // 318767187
|
||||
P_CL2FE_REQ_PC_CHANGE_MENTOR = 0x13000054, // 318767188
|
||||
P_CL2FE_REQ_GET_BUDDY_LOCATION = 0x13000055, // 318767189
|
||||
P_CL2FE_REQ_NPC_GROUP_SUMMON = 0x13000056, // 318767190
|
||||
P_CL2FE_REQ_PC_WARP_TO_PC = 0x13000057, // 318767191
|
||||
P_CL2FE_REQ_EP_RANK_GET_LIST = 0x13000058, // 318767192
|
||||
P_CL2FE_REQ_EP_RANK_GET_DETAIL = 0x13000059, // 318767193
|
||||
P_CL2FE_REQ_EP_RANK_GET_PC_INFO = 0x1300005a, // 318767194
|
||||
P_CL2FE_REQ_EP_RACE_START = 0x1300005b, // 318767195
|
||||
P_CL2FE_REQ_EP_RACE_END = 0x1300005c, // 318767196
|
||||
P_CL2FE_REQ_EP_RACE_CANCEL = 0x1300005d, // 318767197
|
||||
P_CL2FE_REQ_EP_GET_RING = 0x1300005e, // 318767198
|
||||
P_CL2FE_REQ_IM_CHANGE_SWITCH_STATUS = 0x1300005f, // 318767199
|
||||
P_CL2FE_REQ_SHINY_PICKUP = 0x13000060, // 318767200
|
||||
P_CL2FE_REQ_SHINY_SUMMON = 0x13000061, // 318767201
|
||||
P_CL2FE_REQ_PC_MOVETRANSPORTATION = 0x13000062, // 318767202
|
||||
P_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE = 0x13000063, // 318767203
|
||||
P_CL2FE_REQ_SEND_ANY_GROUP_FREECHAT_MESSAGE = 0x13000064, // 318767204
|
||||
P_CL2FE_REQ_BARKER = 0x13000065, // 318767205
|
||||
P_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE = 0x13000066, // 318767206
|
||||
P_CL2FE_REQ_SEND_ANY_GROUP_MENUCHAT_MESSAGE = 0x13000067, // 318767207
|
||||
P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION = 0x13000068, // 318767208
|
||||
P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION = 0x13000069, // 318767209
|
||||
P_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH = 0x1300006a, // 318767210
|
||||
P_CL2FE_GM_REQ_PC_SET_VALUE = 0x1300006b, // 318767211
|
||||
P_CL2FE_GM_REQ_KICK_PLAYER = 0x1300006c, // 318767212
|
||||
P_CL2FE_GM_REQ_TARGET_PC_TELEPORT = 0x1300006d, // 318767213
|
||||
P_CL2FE_GM_REQ_PC_LOCATION = 0x1300006e, // 318767214
|
||||
P_CL2FE_GM_REQ_PC_ANNOUNCE = 0x1300006f, // 318767215
|
||||
P_CL2FE_REQ_SET_PC_BLOCK = 0x13000070, // 318767216
|
||||
P_CL2FE_REQ_REGIST_RXCOM = 0x13000071, // 318767217
|
||||
P_CL2FE_GM_REQ_PC_MOTD_REGISTER = 0x13000072, // 318767218
|
||||
P_CL2FE_REQ_ITEM_USE = 0x13000073, // 318767219
|
||||
P_CL2FE_REQ_WARP_USE_RECALL = 0x13000074, // 318767220
|
||||
P_CL2FE_REP_LIVE_CHECK = 0x13000075, // 318767221
|
||||
P_CL2FE_REQ_PC_MISSION_COMPLETE = 0x13000076, // 318767222
|
||||
P_CL2FE_REQ_PC_TASK_COMPLETE = 0x13000077, // 318767223
|
||||
P_CL2FE_REQ_NPC_INTERACTION = 0x13000078, // 318767224
|
||||
P_CL2FE_DOT_HEAL_ONOFF = 0x13000079, // 318767225
|
||||
P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH = 0x1300007a, // 318767226
|
||||
P_CL2FE_REQ_PC_EMAIL_UPDATE_CHECK = 0x1300007b, // 318767227
|
||||
P_CL2FE_REQ_PC_READ_EMAIL = 0x1300007c, // 318767228
|
||||
P_CL2FE_REQ_PC_RECV_EMAIL_PAGE_LIST = 0x1300007d, // 318767229
|
||||
P_CL2FE_REQ_PC_DELETE_EMAIL = 0x1300007e, // 318767230
|
||||
P_CL2FE_REQ_PC_SEND_EMAIL = 0x1300007f, // 318767231
|
||||
P_CL2FE_REQ_PC_RECV_EMAIL_ITEM = 0x13000080, // 318767232
|
||||
P_CL2FE_REQ_PC_RECV_EMAIL_CANDY = 0x13000081, // 318767233
|
||||
P_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF = 0x13000082, // 318767234
|
||||
P_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID = 0x13000083, // 318767235
|
||||
P_CL2FE_REQ_NPC_GROUP_INVITE = 0x13000084, // 318767236
|
||||
P_CL2FE_REQ_NPC_GROUP_KICK = 0x13000085, // 318767237
|
||||
P_CL2FE_REQ_PC_FIRST_USE_FLAG_SET = 0x13000086, // 318767238
|
||||
P_CL2FE_REQ_PC_TRANSPORT_WARP = 0x13000087, // 318767239
|
||||
P_CL2FE_REQ_PC_TIME_TO_GO_WARP = 0x13000088, // 318767240
|
||||
P_CL2FE_REQ_PC_RECV_EMAIL_ITEM_ALL = 0x13000089, // 318767241
|
||||
P_CL2FE_REQ_CHANNEL_INFO = 0x1300008a, // 318767242
|
||||
P_CL2FE_REQ_PC_CHANNEL_NUM = 0x1300008b, // 318767243
|
||||
P_CL2FE_REQ_PC_WARP_CHANNEL = 0x1300008c, // 318767244
|
||||
P_CL2FE_REQ_PC_LOADING_COMPLETE = 0x1300008d, // 318767245
|
||||
P_CL2FE_REQ_PC_FIND_NAME_MAKE_BUDDY = 0x1300008e, // 318767246
|
||||
P_CL2FE_REQ_PC_FIND_NAME_ACCEPT_BUDDY = 0x1300008f, // 318767247
|
||||
P_CL2FE_REQ_PC_ATTACK_CHARs = 0x13000090, // 318767248
|
||||
P_CL2FE_PC_STREETSTALL_REQ_READY = 0x13000091, // 318767249
|
||||
P_CL2FE_PC_STREETSTALL_REQ_CANCEL = 0x13000092, // 318767250
|
||||
P_CL2FE_PC_STREETSTALL_REQ_REGIST_ITEM = 0x13000093, // 318767251
|
||||
P_CL2FE_PC_STREETSTALL_REQ_UNREGIST_ITEM = 0x13000094, // 318767252
|
||||
P_CL2FE_PC_STREETSTALL_REQ_SALE_START = 0x13000095, // 318767253
|
||||
P_CL2FE_PC_STREETSTALL_REQ_ITEM_LIST = 0x13000096, // 318767254
|
||||
P_CL2FE_PC_STREETSTALL_REQ_ITEM_BUY = 0x13000097, // 318767255
|
||||
P_CL2FE_REQ_PC_ITEM_COMBINATION = 0x13000098, // 318767256
|
||||
P_CL2FE_GM_REQ_SET_PC_SKILL = 0x13000099, // 318767257
|
||||
P_CL2FE_REQ_PC_SKILL_ADD = 0x1300009a, // 318767258
|
||||
P_CL2FE_REQ_PC_SKILL_DEL = 0x1300009b, // 318767259
|
||||
P_CL2FE_REQ_PC_SKILL_USE = 0x1300009c, // 318767260
|
||||
P_CL2FE_REQ_PC_ROPE = 0x1300009d, // 318767261
|
||||
P_CL2FE_REQ_PC_BELT = 0x1300009e, // 318767262
|
||||
P_CL2FE_REQ_PC_VEHICLE_ON = 0x1300009f, // 318767263
|
||||
P_CL2FE_REQ_PC_VEHICLE_OFF = 0x130000a0, // 318767264
|
||||
P_CL2FE_REQ_PC_REGIST_QUICK_SLOT = 0x130000a1, // 318767265
|
||||
P_CL2FE_REQ_PC_DISASSEMBLE_ITEM = 0x130000a2, // 318767266
|
||||
P_CL2FE_GM_REQ_REWARD_RATE = 0x130000a3, // 318767267
|
||||
P_CL2FE_REQ_PC_ITEM_ENCHANT = 0x130000a4, // 318767268
|
||||
|
||||
P_FE2CL_ERROR = 0x31000000, // 822083584
|
||||
P_FE2CL_REP_PC_ENTER_FAIL = 0x31000001, // 822083585
|
||||
P_FE2CL_REP_PC_ENTER_SUCC = 0x31000002, // 822083586
|
||||
P_FE2CL_PC_NEW = 0x31000003, // 822083587
|
||||
P_FE2CL_REP_PC_EXIT_FAIL = 0x31000004, // 822083588
|
||||
P_FE2CL_REP_PC_EXIT_SUCC = 0x31000005, // 822083589
|
||||
P_FE2CL_PC_EXIT = 0x31000006, // 822083590
|
||||
P_FE2CL_PC_AROUND = 0x31000007, // 822083591
|
||||
P_FE2CL_PC_MOVE = 0x31000008, // 822083592
|
||||
P_FE2CL_PC_STOP = 0x31000009, // 822083593
|
||||
P_FE2CL_PC_JUMP = 0x3100000a, // 822083594
|
||||
P_FE2CL_NPC_ENTER = 0x3100000b, // 822083595
|
||||
P_FE2CL_NPC_EXIT = 0x3100000c, // 822083596
|
||||
P_FE2CL_NPC_MOVE = 0x3100000d, // 822083597
|
||||
P_FE2CL_NPC_NEW = 0x3100000e, // 822083598
|
||||
P_FE2CL_NPC_AROUND = 0x3100000f, // 822083599
|
||||
P_FE2CL_AROUND_DEL_PC = 0x31000010, // 822083600
|
||||
P_FE2CL_AROUND_DEL_NPC = 0x31000011, // 822083601
|
||||
P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC = 0x31000012, // 822083602
|
||||
P_FE2CL_REP_SEND_FREECHAT_MESSAGE_FAIL = 0x31000013, // 822083603
|
||||
P_FE2CL_PC_ATTACK_NPCs_SUCC = 0x31000014, // 822083604
|
||||
P_FE2CL_PC_ATTACK_NPCs = 0x31000015, // 822083605
|
||||
P_FE2CL_NPC_ATTACK_PCs = 0x31000016, // 822083606
|
||||
P_FE2CL_REP_PC_REGEN_SUCC = 0x31000017, // 822083607
|
||||
P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC = 0x31000018, // 822083608
|
||||
P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_FAIL = 0x31000019, // 822083609
|
||||
P_FE2CL_PC_ITEM_MOVE_SUCC = 0x3100001a, // 822083610
|
||||
P_FE2CL_PC_EQUIP_CHANGE = 0x3100001b, // 822083611
|
||||
P_FE2CL_REP_PC_TASK_START_SUCC = 0x3100001c, // 822083612
|
||||
P_FE2CL_REP_PC_TASK_START_FAIL = 0x3100001d, // 822083613
|
||||
P_FE2CL_REP_PC_TASK_END_SUCC = 0x3100001e, // 822083614
|
||||
P_FE2CL_REP_PC_TASK_END_FAIL = 0x3100001f, // 822083615
|
||||
P_FE2CL_NPC_SKILL_READY = 0x31000020, // 822083616
|
||||
P_FE2CL_NPC_SKILL_FIRE = 0x31000021, // 822083617
|
||||
P_FE2CL_NPC_SKILL_HIT = 0x31000022, // 822083618
|
||||
P_FE2CL_NPC_SKILL_CORRUPTION_READY = 0x31000023, // 822083619
|
||||
P_FE2CL_NPC_SKILL_CORRUPTION_HIT = 0x31000024, // 822083620
|
||||
P_FE2CL_NPC_SKILL_CANCEL = 0x31000025, // 822083621
|
||||
P_FE2CL_REP_NANO_EQUIP_SUCC = 0x31000026, // 822083622
|
||||
P_FE2CL_REP_NANO_UNEQUIP_SUCC = 0x31000027, // 822083623
|
||||
P_FE2CL_REP_NANO_ACTIVE_SUCC = 0x31000028, // 822083624
|
||||
P_FE2CL_REP_NANO_TUNE_SUCC = 0x31000029, // 822083625
|
||||
P_FE2CL_NANO_ACTIVE = 0x3100002a, // 822083626
|
||||
P_FE2CL_NANO_SKILL_USE_SUCC = 0x3100002b, // 822083627
|
||||
P_FE2CL_NANO_SKILL_USE = 0x3100002c, // 822083628
|
||||
P_FE2CL_REP_PC_TASK_STOP_SUCC = 0x3100002d, // 822083629
|
||||
P_FE2CL_REP_PC_TASK_STOP_FAIL = 0x3100002e, // 822083630
|
||||
P_FE2CL_REP_PC_TASK_CONTINUE_SUCC = 0x3100002f, // 822083631
|
||||
P_FE2CL_REP_PC_TASK_CONTINUE_FAIL = 0x31000030, // 822083632
|
||||
P_FE2CL_REP_PC_GOTO_SUCC = 0x31000031, // 822083633
|
||||
P_FE2CL_REP_CHARGE_NANO_STAMINA = 0x31000032, // 822083634
|
||||
P_FE2CL_REP_PC_TICK = 0x31000033, // 822083635
|
||||
P_FE2CL_REP_PC_KILL_QUEST_NPCs_SUCC = 0x31000034, // 822083636
|
||||
P_FE2CL_REP_PC_VENDOR_ITEM_BUY_SUCC = 0x31000035, // 822083637
|
||||
P_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL = 0x31000036, // 822083638
|
||||
P_FE2CL_REP_PC_VENDOR_ITEM_SELL_SUCC = 0x31000037, // 822083639
|
||||
P_FE2CL_REP_PC_VENDOR_ITEM_SELL_FAIL = 0x31000038, // 822083640
|
||||
P_FE2CL_REP_PC_ITEM_DELETE_SUCC = 0x31000039, // 822083641
|
||||
P_FE2CL_PC_ROCKET_STYLE_READY = 0x3100003a, // 822083642
|
||||
P_FE2CL_REP_PC_ROCKET_STYLE_FIRE_SUCC = 0x3100003b, // 822083643
|
||||
P_FE2CL_PC_ROCKET_STYLE_FIRE = 0x3100003c, // 822083644
|
||||
P_FE2CL_PC_ROCKET_STYLE_HIT = 0x3100003d, // 822083645
|
||||
P_FE2CL_PC_GRENADE_STYLE_READY = 0x3100003e, // 822083646
|
||||
P_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC = 0x3100003f, // 822083647
|
||||
P_FE2CL_PC_GRENADE_STYLE_FIRE = 0x31000040, // 822083648
|
||||
P_FE2CL_PC_GRENADE_STYLE_HIT = 0x31000041, // 822083649
|
||||
P_FE2CL_REP_PC_TRADE_OFFER = 0x31000042, // 822083650
|
||||
P_FE2CL_REP_PC_TRADE_OFFER_CANCEL = 0x31000043, // 822083651
|
||||
P_FE2CL_REP_PC_TRADE_OFFER_SUCC = 0x31000044, // 822083652
|
||||
P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL = 0x31000045, // 822083653
|
||||
P_FE2CL_REP_PC_TRADE_OFFER_ABORT = 0x31000046, // 822083654
|
||||
P_FE2CL_REP_PC_TRADE_CONFIRM = 0x31000047, // 822083655
|
||||
P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL = 0x31000048, // 822083656
|
||||
P_FE2CL_REP_PC_TRADE_CONFIRM_ABORT = 0x31000049, // 822083657
|
||||
P_FE2CL_REP_PC_TRADE_CONFIRM_SUCC = 0x3100004a, // 822083658
|
||||
P_FE2CL_REP_PC_TRADE_CONFIRM_FAIL = 0x3100004b, // 822083659
|
||||
P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC = 0x3100004c, // 822083660
|
||||
P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_FAIL = 0x3100004d, // 822083661
|
||||
P_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC = 0x3100004e, // 822083662
|
||||
P_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_FAIL = 0x3100004f, // 822083663
|
||||
P_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC = 0x31000050, // 822083664
|
||||
P_FE2CL_REP_PC_TRADE_CASH_REGISTER_FAIL = 0x31000051, // 822083665
|
||||
P_FE2CL_REP_PC_TRADE_EMOTES_CHAT = 0x31000052, // 822083666
|
||||
P_FE2CL_REP_PC_NANO_CREATE_SUCC = 0x31000053, // 822083667
|
||||
P_FE2CL_REP_PC_NANO_CREATE_FAIL = 0x31000054, // 822083668
|
||||
P_FE2CL_REP_NANO_TUNE_FAIL = 0x31000055, // 822083669
|
||||
P_FE2CL_REP_PC_BANK_OPEN_SUCC = 0x31000056, // 822083670
|
||||
P_FE2CL_REP_PC_BANK_OPEN_FAIL = 0x31000057, // 822083671
|
||||
P_FE2CL_REP_PC_BANK_CLOSE_SUCC = 0x31000058, // 822083672
|
||||
P_FE2CL_REP_PC_BANK_CLOSE_FAIL = 0x31000059, // 822083673
|
||||
P_FE2CL_REP_PC_VENDOR_START_SUCC = 0x3100005a, // 822083674
|
||||
P_FE2CL_REP_PC_VENDOR_START_FAIL = 0x3100005b, // 822083675
|
||||
P_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_SUCC = 0x3100005c, // 822083676
|
||||
P_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_FAIL = 0x3100005d, // 822083677
|
||||
P_FE2CL_REP_PC_VENDOR_ITEM_RESTORE_BUY_SUCC = 0x3100005e, // 822083678
|
||||
P_FE2CL_REP_PC_VENDOR_ITEM_RESTORE_BUY_FAIL = 0x3100005f, // 822083679
|
||||
P_FE2CL_CHAR_TIME_BUFF_TIME_OUT = 0x31000060, // 822083680
|
||||
P_FE2CL_REP_PC_GIVE_ITEM_SUCC = 0x31000061, // 822083681
|
||||
P_FE2CL_REP_PC_GIVE_ITEM_FAIL = 0x31000062, // 822083682
|
||||
P_FE2CL_REP_PC_BUDDYLIST_INFO_SUCC = 0x31000063, // 822083683
|
||||
P_FE2CL_REP_PC_BUDDYLIST_INFO_FAIL = 0x31000064, // 822083684
|
||||
P_FE2CL_REP_REQUEST_MAKE_BUDDY_SUCC = 0x7fffffff, // 2147483647
|
||||
P_FE2CL_REP_REQUEST_MAKE_BUDDY_FAIL = 0x31000066, // 822083686
|
||||
P_FE2CL_REP_ACCEPT_MAKE_BUDDY_SUCC = 0x31000067, // 822083687
|
||||
P_FE2CL_REP_ACCEPT_MAKE_BUDDY_FAIL = 0x31000068, // 822083688
|
||||
P_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC = 0x31000069, // 822083689
|
||||
P_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_FAIL = 0x3100006a, // 822083690
|
||||
P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC = 0x3100006b, // 822083691
|
||||
P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_FAIL = 0x3100006c, // 822083692
|
||||
P_FE2CL_REP_GET_BUDDY_STYLE_SUCC = 0x3100006d, // 822083693
|
||||
P_FE2CL_REP_GET_BUDDY_STYLE_FAIL = 0x3100006e, // 822083694
|
||||
P_FE2CL_REP_GET_BUDDY_STATE_SUCC = 0x3100006f, // 822083695
|
||||
P_FE2CL_REP_GET_BUDDY_STATE_FAIL = 0x31000070, // 822083696
|
||||
P_FE2CL_REP_SET_BUDDY_BLOCK_SUCC = 0x31000071, // 822083697
|
||||
P_FE2CL_REP_SET_BUDDY_BLOCK_FAIL = 0x31000072, // 822083698
|
||||
P_FE2CL_REP_REMOVE_BUDDY_SUCC = 0x31000073, // 822083699
|
||||
P_FE2CL_REP_REMOVE_BUDDY_FAIL = 0x31000074, // 822083700
|
||||
P_FE2CL_PC_JUMPPAD = 0x31000075, // 822083701
|
||||
P_FE2CL_PC_LAUNCHER = 0x31000076, // 822083702
|
||||
P_FE2CL_PC_ZIPLINE = 0x31000077, // 822083703
|
||||
P_FE2CL_PC_MOVEPLATFORM = 0x31000078, // 822083704
|
||||
P_FE2CL_PC_SLOPE = 0x31000079, // 822083705
|
||||
P_FE2CL_PC_STATE_CHANGE = 0x3100007a, // 822083706
|
||||
P_FE2CL_REP_REQUEST_MAKE_BUDDY_SUCC_TO_ACCEPTER = 0x3100007b, // 822083707
|
||||
P_FE2CL_REP_REWARD_ITEM = 0x3100007c, // 822083708
|
||||
P_FE2CL_REP_ITEM_CHEST_OPEN_SUCC = 0x3100007d, // 822083709
|
||||
P_FE2CL_REP_ITEM_CHEST_OPEN_FAIL = 0x3100007e, // 822083710
|
||||
P_FE2CL_CHAR_TIME_BUFF_TIME_TICK = 0x3100007f, // 822083711
|
||||
P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC = 0x31000080, // 822083712
|
||||
P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_FAIL = 0x31000081, // 822083713
|
||||
P_FE2CL_NPC_ROCKET_STYLE_FIRE = 0x31000082, // 822083714
|
||||
P_FE2CL_NPC_GRENADE_STYLE_FIRE = 0x31000083, // 822083715
|
||||
P_FE2CL_NPC_BULLET_STYLE_HIT = 0x31000084, // 822083716
|
||||
P_FE2CL_CHARACTER_ATTACK_CHARACTERs = 0x31000085, // 822083717
|
||||
P_FE2CL_PC_GROUP_INVITE = 0x31000086, // 822083718
|
||||
P_FE2CL_PC_GROUP_INVITE_FAIL = 0x31000087, // 822083719
|
||||
P_FE2CL_PC_GROUP_INVITE_REFUSE = 0x31000088, // 822083720
|
||||
P_FE2CL_PC_GROUP_JOIN = 0x31000089, // 822083721
|
||||
P_FE2CL_PC_GROUP_JOIN_FAIL = 0x3100008a, // 822083722
|
||||
P_FE2CL_PC_GROUP_JOIN_SUCC = 0x3100008b, // 822083723
|
||||
P_FE2CL_PC_GROUP_LEAVE = 0x3100008c, // 822083724
|
||||
P_FE2CL_PC_GROUP_LEAVE_FAIL = 0x3100008d, // 822083725
|
||||
P_FE2CL_PC_GROUP_LEAVE_SUCC = 0x3100008e, // 822083726
|
||||
P_FE2CL_PC_GROUP_MEMBER_INFO = 0x3100008f, // 822083727
|
||||
P_FE2CL_REP_PC_WARP_USE_NPC_SUCC = 0x31000090, // 822083728
|
||||
P_FE2CL_REP_PC_WARP_USE_NPC_FAIL = 0x31000091, // 822083729
|
||||
P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT = 0x31000092, // 822083730
|
||||
P_FE2CL_REP_PC_CHANGE_MENTOR_SUCC = 0x31000093, // 822083731
|
||||
P_FE2CL_REP_PC_CHANGE_MENTOR_FAIL = 0x31000094, // 822083732
|
||||
P_FE2CL_REP_GET_MEMBER_STYLE_FAIL = 0x31000095, // 822083733
|
||||
P_FE2CL_REP_GET_MEMBER_STYLE_SUCC = 0x31000096, // 822083734
|
||||
P_FE2CL_REP_GET_GROUP_STYLE_FAIL = 0x31000097, // 822083735
|
||||
P_FE2CL_REP_GET_GROUP_STYLE_SUCC = 0x31000098, // 822083736
|
||||
P_FE2CL_PC_REGEN = 0x31000099, // 822083737
|
||||
P_FE2CL_INSTANCE_MAP_INFO = 0x3100009a, // 822083738
|
||||
P_FE2CL_TRANSPORTATION_ENTER = 0x3100009b, // 822083739
|
||||
P_FE2CL_TRANSPORTATION_EXIT = 0x3100009c, // 822083740
|
||||
P_FE2CL_TRANSPORTATION_MOVE = 0x3100009d, // 822083741
|
||||
P_FE2CL_TRANSPORTATION_NEW = 0x3100009e, // 822083742
|
||||
P_FE2CL_TRANSPORTATION_AROUND = 0x3100009f, // 822083743
|
||||
P_FE2CL_AROUND_DEL_TRANSPORTATION = 0x310000a0, // 822083744
|
||||
P_FE2CL_REP_EP_RANK_LIST = 0x310000a1, // 822083745
|
||||
P_FE2CL_REP_EP_RANK_DETAIL = 0x310000a2, // 822083746
|
||||
P_FE2CL_REP_EP_RANK_PC_INFO = 0x310000a3, // 822083747
|
||||
P_FE2CL_REP_EP_RACE_START_SUCC = 0x310000a4, // 822083748
|
||||
P_FE2CL_REP_EP_RACE_START_FAIL = 0x310000a5, // 822083749
|
||||
P_FE2CL_REP_EP_RACE_END_SUCC = 0x310000a6, // 822083750
|
||||
P_FE2CL_REP_EP_RACE_END_FAIL = 0x310000a7, // 822083751
|
||||
P_FE2CL_REP_EP_RACE_CANCEL_SUCC = 0x310000a8, // 822083752
|
||||
P_FE2CL_REP_EP_RACE_CANCEL_FAIL = 0x310000a9, // 822083753
|
||||
P_FE2CL_REP_EP_GET_RING_SUCC = 0x310000aa, // 822083754
|
||||
P_FE2CL_REP_EP_GET_RING_FAIL = 0x310000ab, // 822083755
|
||||
P_FE2CL_REP_IM_CHANGE_SWITCH_STATUS = 0x310000ac, // 822083756
|
||||
P_FE2CL_SHINY_ENTER = 0x310000ad, // 822083757
|
||||
P_FE2CL_SHINY_EXIT = 0x310000ae, // 822083758
|
||||
P_FE2CL_SHINY_NEW = 0x310000af, // 822083759
|
||||
P_FE2CL_SHINY_AROUND = 0x310000b0, // 822083760
|
||||
P_FE2CL_AROUND_DEL_SHINY = 0x310000b1, // 822083761
|
||||
P_FE2CL_REP_SHINY_PICKUP_FAIL = 0x310000b2, // 822083762
|
||||
P_FE2CL_REP_SHINY_PICKUP_SUCC = 0x310000b3, // 822083763
|
||||
P_FE2CL_PC_MOVETRANSPORTATION = 0x310000b4, // 822083764
|
||||
P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC = 0x310000b5, // 822083765
|
||||
P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_FAIL = 0x310000b6, // 822083766
|
||||
P_FE2CL_REP_SEND_ANY_GROUP_FREECHAT_MESSAGE_SUCC = 0x310000b7, // 822083767
|
||||
P_FE2CL_REP_SEND_ANY_GROUP_FREECHAT_MESSAGE_FAIL = 0x310000b8, // 822083768
|
||||
P_FE2CL_REP_BARKER = 0x310000b9, // 822083769
|
||||
P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC = 0x310000ba, // 822083770
|
||||
P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_FAIL = 0x310000bb, // 822083771
|
||||
P_FE2CL_REP_SEND_ANY_GROUP_MENUCHAT_MESSAGE_SUCC = 0x310000bc, // 822083772
|
||||
P_FE2CL_REP_SEND_ANY_GROUP_MENUCHAT_MESSAGE_FAIL = 0x310000bd, // 822083773
|
||||
P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL = 0x310000be, // 822083774
|
||||
P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC = 0x310000bf, // 822083775
|
||||
P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_FAIL = 0x310000c0, // 822083776
|
||||
P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC = 0x310000c1, // 822083777
|
||||
P_FE2CL_ANNOUNCE_MSG = 0x310000c2, // 822083778
|
||||
P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC = 0x310000c3, // 822083779
|
||||
P_FE2CL_PC_SPECIAL_STATE_CHANGE = 0x310000c4, // 822083780
|
||||
P_FE2CL_GM_REP_PC_SET_VALUE = 0x310000c5, // 822083781
|
||||
P_FE2CL_GM_PC_CHANGE_VALUE = 0x310000c6, // 822083782
|
||||
P_FE2CL_GM_REP_PC_LOCATION = 0x310000c7, // 822083783
|
||||
P_FE2CL_GM_REP_PC_ANNOUNCE = 0x310000c8, // 822083784
|
||||
P_FE2CL_REP_PC_BUDDY_WARP_FAIL = 0x310000c9, // 822083785
|
||||
P_FE2CL_REP_PC_CHANGE_LEVEL = 0x310000ca, // 822083786
|
||||
P_FE2CL_REP_SET_PC_BLOCK_SUCC = 0x310000cb, // 822083787
|
||||
P_FE2CL_REP_SET_PC_BLOCK_FAIL = 0x310000cc, // 822083788
|
||||
P_FE2CL_REP_REGIST_RXCOM = 0x310000cd, // 822083789
|
||||
P_FE2CL_REP_REGIST_RXCOM_FAIL = 0x310000ce, // 822083790
|
||||
P_FE2CL_PC_INVEN_FULL_MSG = 0x310000cf, // 822083791
|
||||
P_FE2CL_REQ_LIVE_CHECK = 0x310000d0, // 822083792
|
||||
P_FE2CL_PC_MOTD_LOGIN = 0x310000d1, // 822083793
|
||||
P_FE2CL_REP_PC_ITEM_USE_FAIL = 0x310000d2, // 822083794
|
||||
P_FE2CL_REP_PC_ITEM_USE_SUCC = 0x310000d3, // 822083795
|
||||
P_FE2CL_PC_ITEM_USE = 0x310000d4, // 822083796
|
||||
P_FE2CL_REP_GET_BUDDY_LOCATION_SUCC = 0x310000d5, // 822083797
|
||||
P_FE2CL_REP_GET_BUDDY_LOCATION_FAIL = 0x310000d6, // 822083798
|
||||
P_FE2CL_REP_PC_RIDING_FAIL = 0x310000d7, // 822083799
|
||||
P_FE2CL_REP_PC_RIDING_SUCC = 0x310000d8, // 822083800
|
||||
P_FE2CL_PC_RIDING = 0x310000d9, // 822083801
|
||||
P_FE2CL_PC_BROOMSTICK_MOVE = 0x310000da, // 822083802
|
||||
P_FE2CL_REP_PC_BUDDY_WARP_OTHER_SHARD_SUCC = 0x310000db, // 822083803
|
||||
P_FE2CL_REP_WARP_USE_RECALL_FAIL = 0x310000dc, // 822083804
|
||||
P_FE2CL_REP_PC_EXIT_DUPLICATE = 0x310000dd, // 822083805
|
||||
P_FE2CL_REP_PC_MISSION_COMPLETE_SUCC = 0x310000de, // 822083806
|
||||
P_FE2CL_PC_BUFF_UPDATE = 0x310000df, // 822083807
|
||||
P_FE2CL_REP_PC_NEW_EMAIL = 0x310000e0, // 822083808
|
||||
P_FE2CL_REP_PC_READ_EMAIL_SUCC = 0x310000e1, // 822083809
|
||||
P_FE2CL_REP_PC_READ_EMAIL_FAIL = 0x310000e2, // 822083810
|
||||
P_FE2CL_REP_PC_RECV_EMAIL_PAGE_LIST_SUCC = 0x310000e3, // 822083811
|
||||
P_FE2CL_REP_PC_RECV_EMAIL_PAGE_LIST_FAIL = 0x310000e4, // 822083812
|
||||
P_FE2CL_REP_PC_DELETE_EMAIL_SUCC = 0x310000e5, // 822083813
|
||||
P_FE2CL_REP_PC_DELETE_EMAIL_FAIL = 0x310000e6, // 822083814
|
||||
P_FE2CL_REP_PC_SEND_EMAIL_SUCC = 0x310000e7, // 822083815
|
||||
P_FE2CL_REP_PC_SEND_EMAIL_FAIL = 0x310000e8, // 822083816
|
||||
P_FE2CL_REP_PC_RECV_EMAIL_ITEM_SUCC = 0x310000e9, // 822083817
|
||||
P_FE2CL_REP_PC_RECV_EMAIL_ITEM_FAIL = 0x310000ea, // 822083818
|
||||
P_FE2CL_REP_PC_RECV_EMAIL_CANDY_SUCC = 0x310000eb, // 822083819
|
||||
P_FE2CL_REP_PC_RECV_EMAIL_CANDY_FAIL = 0x310000ec, // 822083820
|
||||
P_FE2CL_PC_SUDDEN_DEAD = 0x310000ed, // 822083821
|
||||
P_FE2CL_REP_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF_SUCC = 0x310000ee, // 822083822
|
||||
P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID = 0x310000ef, // 822083823
|
||||
P_FE2CL_REP_NPC_GROUP_INVITE_FAIL = 0x310000f0, // 822083824
|
||||
P_FE2CL_REP_NPC_GROUP_INVITE_SUCC = 0x310000f1, // 822083825
|
||||
P_FE2CL_REP_NPC_GROUP_KICK_FAIL = 0x310000f2, // 822083826
|
||||
P_FE2CL_REP_NPC_GROUP_KICK_SUCC = 0x310000f3, // 822083827
|
||||
P_FE2CL_PC_EVENT = 0x310000f4, // 822083828
|
||||
P_FE2CL_REP_PC_TRANSPORT_WARP_SUCC = 0x310000f5, // 822083829
|
||||
P_FE2CL_REP_PC_TRADE_EMOTES_CHAT_FAIL = 0x310000f6, // 822083830
|
||||
P_FE2CL_REP_PC_RECV_EMAIL_ITEM_ALL_SUCC = 0x310000f7, // 822083831
|
||||
P_FE2CL_REP_PC_RECV_EMAIL_ITEM_ALL_FAIL = 0x310000f8, // 822083832
|
||||
P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC = 0x310000f9, // 822083833
|
||||
P_FE2CL_REP_CHANNEL_INFO = 0x310000fa, // 822083834
|
||||
P_FE2CL_REP_PC_CHANNEL_NUM = 0x310000fb, // 822083835
|
||||
P_FE2CL_REP_PC_WARP_CHANNEL_FAIL = 0x310000fc, // 822083836
|
||||
P_FE2CL_REP_PC_WARP_CHANNEL_SUCC = 0x310000fd, // 822083837
|
||||
P_FE2CL_REP_PC_FIND_NAME_MAKE_BUDDY_SUCC = 0x310000fe, // 822083838
|
||||
P_FE2CL_REP_PC_FIND_NAME_MAKE_BUDDY_FAIL = 0x310000ff, // 822083839
|
||||
P_FE2CL_REP_PC_FIND_NAME_ACCEPT_BUDDY_FAIL = 0x31000100, // 822083840
|
||||
P_FE2CL_REP_PC_BUDDY_WARP_SAME_SHARD_SUCC = 0x31000101, // 822083841
|
||||
P_FE2CL_PC_ATTACK_CHARs_SUCC = 0x31000102, // 822083842
|
||||
P_FE2CL_PC_ATTACK_CHARs = 0x31000103, // 822083843
|
||||
P_FE2CL_NPC_ATTACK_CHARs = 0x31000104, // 822083844
|
||||
P_FE2CL_REP_PC_CHANGE_LEVEL_SUCC = 0x31000105, // 822083845
|
||||
P_FE2CL_REP_PC_NANO_CREATE = 0x31000106, // 822083846
|
||||
P_FE2CL_PC_STREETSTALL_REP_READY_SUCC = 0x31000107, // 822083847
|
||||
P_FE2CL_PC_STREETSTALL_REP_READY_FAIL = 0x31000108, // 822083848
|
||||
P_FE2CL_PC_STREETSTALL_REP_CANCEL_SUCC = 0x31000109, // 822083849
|
||||
P_FE2CL_PC_STREETSTALL_REP_CANCEL_FAIL = 0x3100010a, // 822083850
|
||||
P_FE2CL_PC_STREETSTALL_REP_REGIST_ITEM_SUCC = 0x3100010b, // 822083851
|
||||
P_FE2CL_PC_STREETSTALL_REP_REGIST_ITEM_FAIL = 0x3100010c, // 822083852
|
||||
P_FE2CL_PC_STREETSTALL_REP_UNREGIST_ITEM_SUCC = 0x3100010d, // 822083853
|
||||
P_FE2CL_PC_STREETSTALL_REP_UNREGIST_ITEM_FAIL = 0x3100010e, // 822083854
|
||||
P_FE2CL_PC_STREETSTALL_REP_SALE_START_SUCC = 0x3100010f, // 822083855
|
||||
P_FE2CL_PC_STREETSTALL_REP_SALE_START_FAIL = 0x31000110, // 822083856
|
||||
P_FE2CL_PC_STREETSTALL_REP_ITEM_LIST = 0x31000111, // 822083857
|
||||
P_FE2CL_PC_STREETSTALL_REP_ITEM_LIST_FAIL = 0x31000112, // 822083858
|
||||
P_FE2CL_PC_STREETSTALL_REP_ITEM_BUY_SUCC_BUYER = 0x31000113, // 822083859
|
||||
P_FE2CL_PC_STREETSTALL_REP_ITEM_BUY_SUCC_SELLER = 0x31000114, // 822083860
|
||||
P_FE2CL_PC_STREETSTALL_REP_ITEM_BUY_FAIL = 0x31000115, // 822083861
|
||||
P_FE2CL_REP_PC_ITEM_COMBINATION_SUCC = 0x31000116, // 822083862
|
||||
P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL = 0x31000117, // 822083863
|
||||
P_FE2CL_PC_CASH_BUFF_UPDATE = 0x31000118, // 822083864
|
||||
P_FE2CL_REP_PC_SKILL_ADD_SUCC = 0x31000119, // 822083865
|
||||
P_FE2CL_REP_PC_SKILL_ADD_FAIL = 0x3100011a, // 822083866
|
||||
P_FE2CL_REP_PC_SKILL_DEL_SUCC = 0x3100011b, // 822083867
|
||||
P_FE2CL_REP_PC_SKILL_DEL_FAIL = 0x3100011c, // 822083868
|
||||
P_FE2CL_REP_PC_SKILL_USE_SUCC = 0x3100011d, // 822083869
|
||||
P_FE2CL_REP_PC_SKILL_USE_FAIL = 0x3100011e, // 822083870
|
||||
P_FE2CL_PC_SKILL_USE = 0x3100011f, // 822083871
|
||||
P_FE2CL_PC_ROPE = 0x31000120, // 822083872
|
||||
P_FE2CL_PC_BELT = 0x31000121, // 822083873
|
||||
P_FE2CL_PC_VEHICLE_ON_SUCC = 0x31000122, // 822083874
|
||||
P_FE2CL_PC_VEHICLE_ON_FAIL = 0x31000123, // 822083875
|
||||
P_FE2CL_PC_VEHICLE_OFF_SUCC = 0x31000124, // 822083876
|
||||
P_FE2CL_PC_VEHICLE_OFF_FAIL = 0x31000125, // 822083877
|
||||
P_FE2CL_PC_QUICK_SLOT_INFO = 0x31000126, // 822083878
|
||||
P_FE2CL_REP_PC_REGIST_QUICK_SLOT_FAIL = 0x31000127, // 822083879
|
||||
P_FE2CL_REP_PC_REGIST_QUICK_SLOT_SUCC = 0x31000128, // 822083880
|
||||
P_FE2CL_PC_DELETE_TIME_LIMIT_ITEM = 0x31000129, // 822083881
|
||||
P_FE2CL_REP_PC_DISASSEMBLE_ITEM_SUCC = 0x3100012a, // 822083882
|
||||
P_FE2CL_REP_PC_DISASSEMBLE_ITEM_FAIL = 0x3100012b, // 822083883
|
||||
P_FE2CL_GM_REP_REWARD_RATE_SUCC = 0x3100012c, // 822083884
|
||||
P_FE2CL_REP_PC_ITEM_ENCHANT_SUCC = 0x3100012d, // 822083885
|
||||
P_FE2CL_REP_PC_ITEM_ENCHANT_FAIL = 0x3100012e, // 822083886
|
||||
|
||||
P_LS2CL_REP_LOGIN_SUCC = 0x21000001, // 553648129
|
||||
P_LS2CL_REP_LOGIN_FAIL = 0x21000002, // 553648130
|
||||
P_LS2CL_REP_CHAR_INFO = 0x21000003, // 553648131
|
||||
P_LS2CL_REP_CHECK_CHAR_NAME_SUCC = 0x21000005, // 553648133
|
||||
P_LS2CL_REP_CHECK_CHAR_NAME_FAIL = 0x21000006, // 553648134
|
||||
P_LS2CL_REP_SAVE_CHAR_NAME_SUCC = 0x21000007, // 553648135
|
||||
P_LS2CL_REP_SAVE_CHAR_NAME_FAIL = 0x21000008, // 553648136
|
||||
P_LS2CL_REP_CHAR_CREATE_SUCC = 0x21000009, // 553648137
|
||||
P_LS2CL_REP_CHAR_CREATE_FAIL = 0x2100000a, // 553648138
|
||||
P_LS2CL_REP_CHAR_SELECT_SUCC = 0x2100000b, // 553648139
|
||||
P_LS2CL_REP_CHAR_SELECT_FAIL = 0x2100000c, // 553648140
|
||||
P_LS2CL_REP_CHAR_DELETE_SUCC = 0x2100000d, // 553648141
|
||||
P_LS2CL_REP_CHAR_DELETE_FAIL = 0x2100000e, // 553648142
|
||||
P_LS2CL_REP_SHARD_SELECT_SUCC = 0x2100000f, // 553648143
|
||||
P_LS2CL_REP_SHARD_SELECT_FAIL = 0x21000010, // 553648144
|
||||
P_LS2CL_REP_VERSION_CHECK_SUCC = 0x21000011, // 553648145
|
||||
P_LS2CL_REP_VERSION_CHECK_FAIL = 0x21000012, // 553648146
|
||||
P_LS2CL_REP_CHECK_NAME_LIST_SUCC = 0x21000013, // 553648147
|
||||
P_LS2CL_REP_CHECK_NAME_LIST_FAIL = 0x21000014, // 553648148
|
||||
P_LS2CL_REP_PC_EXIT_DUPLICATE = 0x21000015, // 553648149
|
||||
P_LS2CL_REQ_LIVE_CHECK = 0x21000016, // 553648150
|
||||
P_LS2CL_REP_CHANGE_CHAR_NAME_SUCC = 0x21000017, // 553648151
|
||||
P_LS2CL_REP_CHANGE_CHAR_NAME_FAIL = 0x21000018, // 553648152
|
||||
P_LS2CL_REP_SHARD_LIST_INFO_SUCC = 0x21000019, // 553648153
|
||||
};
|
||||
|
||||
/*
|
||||
* Numbers of packets by type.
|
||||
* Each is the last packet - the upper bits + 1
|
||||
*/
|
||||
enum {
|
||||
N_CL2LS = 0xf,
|
||||
N_CL2FE = 0xa5,
|
||||
N_FE2CL = 0x12f,
|
||||
N_LS2CL = 0x1a,
|
||||
|
||||
N_PACKETS = N_CL2LS + N_CL2FE + N_FE2CL + N_LS2CL
|
||||
};
|
||||
|
||||
namespace Defines {
|
||||
std::string p2str(int type, int val);
|
||||
}
|
731
src/ItemManager.cpp
Normal file
731
src/ItemManager.cpp
Normal file
@@ -0,0 +1,731 @@
|
||||
#include "CNShardServer.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "ItemManager.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
#include <string.h> // for memset() and memcmp()
|
||||
#include <assert.h>
|
||||
|
||||
void ItemManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_ITEM, itemGMGiveHandler);
|
||||
//Trade handlers
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER, itemTradeOfferHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT, itemTradeOfferAcceptHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL, itemTradeOfferRefusalHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CONFIRM, itemTradeConfirmHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL, itemTradeConfirmCancelHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER, itemTradeRegisterItemHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER, itemTradeUnregisterItemHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CASH_REGISTER, itemTradeRegisterCashHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT, itemTradeChatHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_CHEST_OPEN, chestOpenHandler);
|
||||
}
|
||||
|
||||
void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_MOVE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_ITEM_MOVE* itemmove = (sP_CL2FE_REQ_ITEM_MOVE*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_PC_ITEM_MOVE_SUCC, resp);
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
|
||||
if (plr.plr->Equip[itemmove->iFromSlotNum].iType != 0 && itemmove->eFrom == 0 && itemmove->eTo == 0) {
|
||||
// this packet should never happen unless it is a weapon, tell the client to do nothing and do nothing ourself
|
||||
resp.eTo = itemmove->eFrom;
|
||||
resp.iToSlotNum = itemmove->iFromSlotNum;
|
||||
resp.ToSlotItem = plr.plr->Equip[itemmove->iToSlotNum];
|
||||
resp.eFrom = itemmove->eTo;
|
||||
resp.iFromSlotNum = itemmove->iToSlotNum;
|
||||
resp.FromSlotItem = plr.plr->Equip[itemmove->iFromSlotNum];
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_PC_ITEM_MOVE_SUCC, sizeof(sP_FE2CL_PC_ITEM_MOVE_SUCC));
|
||||
return;
|
||||
}
|
||||
|
||||
if (itemmove->iToSlotNum > AINVEN_COUNT || itemmove->iToSlotNum < 0)
|
||||
return; // sanity checks
|
||||
|
||||
sItemBase fromItem;
|
||||
sItemBase toItem;
|
||||
|
||||
// eFrom 0 means from equip
|
||||
if (itemmove->eFrom == 0) {
|
||||
// unequiping an item
|
||||
fromItem = plr.plr->Equip[itemmove->iFromSlotNum];
|
||||
} else {
|
||||
fromItem = plr.plr->Inven[itemmove->iFromSlotNum];
|
||||
}
|
||||
|
||||
// eTo 0 means to equip
|
||||
if (itemmove->eTo == 0) {
|
||||
// equiping an item
|
||||
toItem = plr.plr->Equip[itemmove->iToSlotNum];
|
||||
plr.plr->Equip[itemmove->iToSlotNum] = fromItem;
|
||||
} else {
|
||||
toItem = plr.plr->Inven[itemmove->iToSlotNum];
|
||||
plr.plr->Inven[itemmove->iToSlotNum] = fromItem;
|
||||
}
|
||||
|
||||
if (itemmove->eFrom == 0) {
|
||||
plr.plr->Equip[itemmove->iFromSlotNum] = toItem;
|
||||
} else {
|
||||
plr.plr->Inven[itemmove->iFromSlotNum] = toItem;
|
||||
}
|
||||
|
||||
if (itemmove->eFrom == 0 || itemmove->eTo == 0) {
|
||||
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, equipChange);
|
||||
|
||||
equipChange.iPC_ID = plr.plr->iID;
|
||||
if (itemmove->eFrom == 0) {
|
||||
equipChange.iEquipSlotNum = itemmove->iFromSlotNum;
|
||||
equipChange.EquipSlotItem = toItem;
|
||||
} else {
|
||||
equipChange.iEquipSlotNum = itemmove->iToSlotNum;
|
||||
equipChange.EquipSlotItem = fromItem;
|
||||
}
|
||||
|
||||
// unequip vehicle if equip slot 8 is 0
|
||||
if (plr.plr->Equip[8].iID == 0)
|
||||
plr.plr->iPCState = 0;
|
||||
|
||||
// send equip event to other players
|
||||
for (CNSocket* otherSock : plr.viewable) {
|
||||
otherSock->sendPacket((void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
|
||||
}
|
||||
}
|
||||
|
||||
resp.eTo = itemmove->eFrom;
|
||||
resp.iToSlotNum = itemmove->iFromSlotNum;
|
||||
resp.ToSlotItem = toItem;
|
||||
resp.eFrom = itemmove->eTo;
|
||||
resp.iFromSlotNum = itemmove->iToSlotNum;
|
||||
resp.FromSlotItem = fromItem;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_PC_ITEM_MOVE_SUCC, sizeof(sP_FE2CL_PC_ITEM_MOVE_SUCC));
|
||||
}
|
||||
|
||||
void ItemManager::itemDeleteHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_ITEM_DELETE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_ITEM_DELETE* itemdel = (sP_CL2FE_REQ_PC_ITEM_DELETE*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_DELETE_SUCC, resp);
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
|
||||
resp.eIL = itemdel->eIL;
|
||||
resp.iSlotNum = itemdel->iSlotNum;
|
||||
|
||||
// so, im not sure what this eIL thing does since you always delete items in inventory and not equips
|
||||
plr.plr->Inven[itemdel->iSlotNum].iID = 0;
|
||||
plr.plr->Inven[itemdel->iSlotNum].iType = 0;
|
||||
plr.plr->Inven[itemdel->iSlotNum].iOpt = 0;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_ITEM_DELETE_SUCC, sizeof(sP_FE2CL_REP_PC_ITEM_DELETE_SUCC));
|
||||
}
|
||||
|
||||
void ItemManager::itemGMGiveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_ITEM))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_GIVE_ITEM* itemreq = (sP_CL2FE_REQ_PC_GIVE_ITEM*)data->buf;
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
|
||||
// Commented and disabled for future use
|
||||
//if (!plr.plr->IsGM) {
|
||||
// TODO: send fail packet
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (itemreq->eIL == 2) {
|
||||
// Quest item, not a real item, handle this later, stubbed for now
|
||||
// sock->sendPacket(new CNPacketData((void*)resp, P_FE2CL_REP_PC_GIVE_ITEM_FAIL, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_FAIL), sock->getFEKey()));
|
||||
} else if (itemreq->eIL == 1 && itemreq->Item.iType >= 0 && itemreq->Item.iType <= 10) {
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC, resp);
|
||||
|
||||
resp.eIL = itemreq->eIL;
|
||||
resp.iSlotNum = itemreq->iSlotNum;
|
||||
resp.Item = itemreq->Item;
|
||||
|
||||
plr.plr->Inven[itemreq->iSlotNum] = itemreq->Item;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_GIVE_ITEM_SUCC, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC));
|
||||
}
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeOfferHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_OFFER))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TRADE_OFFER* pacdat = (sP_CL2FE_REQ_PC_TRADE_OFFER*)data->buf;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerView& plr = PlayerManager::players[otherSock];
|
||||
|
||||
if (plr.plr->isTrading) {
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_To;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL));
|
||||
|
||||
return; //prevent trading with a player already trading
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER));
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeOfferAcceptHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT* pacdat = (sP_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT*)data->buf;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
// Clearing up trade slots
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
PlayerView& plr2 = PlayerManager::players[otherSock];
|
||||
|
||||
if (plr2.plr->isTrading) {
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_To;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL));
|
||||
|
||||
return; //prevent trading with a player already trading
|
||||
}
|
||||
|
||||
plr.plr->isTrading = true;
|
||||
plr2.plr->isTrading = true;
|
||||
plr.plr->isTradeConfirm = false;
|
||||
plr2.plr->isTradeConfirm = false;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
plr.plr->Trade[i].iID = 0;
|
||||
plr.plr->Trade[i].iType = 0;
|
||||
plr.plr->Trade[i].iOpt = 0;
|
||||
plr.plr->Trade[i].iInvenNum = 0;
|
||||
plr.plr->Trade[i].iSlotNum = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
plr2.plr->Trade[i].iID = 0;
|
||||
plr2.plr->Trade[i].iType = 0;
|
||||
plr2.plr->Trade[i].iOpt = 0;
|
||||
plr2.plr->Trade[i].iInvenNum = 0;
|
||||
plr2.plr->Trade[i].iSlotNum = 0;
|
||||
}
|
||||
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_SUCC));
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeOfferRefusalHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL* pacdat = (sP_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL));
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeConfirmHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_CONFIRM))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TRADE_CONFIRM* pacdat = (sP_CL2FE_REQ_PC_TRADE_CONFIRM*)data->buf;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
PlayerView& plr2 = PlayerManager::players[otherSock];
|
||||
|
||||
if (plr2.plr->isTradeConfirm) {
|
||||
|
||||
plr.plr->isTrading = false;
|
||||
plr2.plr->isTrading = false;
|
||||
plr.plr->isTradeConfirm = false;
|
||||
plr2.plr->isTradeConfirm = false;
|
||||
|
||||
// Check if we have enough free slots
|
||||
int freeSlots = 0;
|
||||
int freeSlotsNeeded = 0;
|
||||
int freeSlots2 = 0;
|
||||
int freeSlotsNeeded2 = 0;
|
||||
|
||||
for (int i = 0; i < AINVEN_COUNT; i++) {
|
||||
if (plr.plr->Inven[i].iID == 0)
|
||||
freeSlots++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (plr.plr->Trade[i].iID != 0)
|
||||
freeSlotsNeeded++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < AINVEN_COUNT; i++) {
|
||||
if (plr2.plr->Inven[i].iID == 0)
|
||||
freeSlots2++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (plr2.plr->Trade[i].iID != 0)
|
||||
freeSlotsNeeded2++;
|
||||
}
|
||||
|
||||
if (freeSlotsNeeded2 - freeSlotsNeeded > freeSlots) {
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT));
|
||||
return; // Fail trade because of the lack of slots
|
||||
}
|
||||
|
||||
if (freeSlotsNeeded - freeSlotsNeeded2 > freeSlots2) {
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL));
|
||||
return; // Fail trade because of the lack of slots
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM));
|
||||
// ^^ this is a must have or else the player won't accept a succ packet for some reason
|
||||
|
||||
for (int i = 0; i < freeSlotsNeeded; i++) {
|
||||
plr.plr->Inven[plr.plr->Trade[i].iInvenNum].iID = 0;
|
||||
plr.plr->Inven[plr.plr->Trade[i].iInvenNum].iType = 0;
|
||||
plr.plr->Inven[plr.plr->Trade[i].iInvenNum].iOpt = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < freeSlotsNeeded2; i++) {
|
||||
plr2.plr->Inven[plr2.plr->Trade[i].iInvenNum].iID = 0;
|
||||
plr2.plr->Inven[plr2.plr->Trade[i].iInvenNum].iType = 0;
|
||||
plr2.plr->Inven[plr2.plr->Trade[i].iInvenNum].iOpt = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < AINVEN_COUNT; i++) {
|
||||
if (freeSlotsNeeded <= 0)
|
||||
break;
|
||||
|
||||
if (plr2.plr->Inven[i].iID == 0) {
|
||||
|
||||
plr2.plr->Inven[i].iID = plr.plr->Trade[freeSlotsNeeded - 1].iID;
|
||||
plr2.plr->Inven[i].iType = plr.plr->Trade[freeSlotsNeeded - 1].iType;
|
||||
plr2.plr->Inven[i].iOpt = plr.plr->Trade[freeSlotsNeeded - 1].iOpt;
|
||||
plr.plr->Trade[freeSlotsNeeded - 1].iInvenNum = i;
|
||||
freeSlotsNeeded--;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < AINVEN_COUNT; i++) {
|
||||
if (freeSlotsNeeded2 <= 0)
|
||||
break;
|
||||
|
||||
if (plr.plr->Inven[i].iID == 0) {
|
||||
|
||||
plr.plr->Inven[i].iID = plr2.plr->Trade[freeSlotsNeeded2 - 1].iID;
|
||||
plr.plr->Inven[i].iType = plr2.plr->Trade[freeSlotsNeeded2 - 1].iType;
|
||||
plr.plr->Inven[i].iOpt = plr2.plr->Trade[freeSlotsNeeded2 - 1].iOpt;
|
||||
plr2.plr->Trade[freeSlotsNeeded2 - 1].iInvenNum = i;
|
||||
freeSlotsNeeded2--;
|
||||
}
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_SUCC, resp2);
|
||||
|
||||
resp2.iID_Request = pacdat->iID_Request;
|
||||
resp2.iID_From = pacdat->iID_From;
|
||||
resp2.iID_To = pacdat->iID_To;
|
||||
|
||||
plr.plr->money = plr.plr->money + plr2.plr->moneyInTrade - plr.plr->moneyInTrade;
|
||||
resp2.iCandy = plr.plr->money;
|
||||
|
||||
memcpy(resp2.Item, plr2.plr->Trade, sizeof(plr2.plr->Trade));
|
||||
memcpy(resp2.ItemStay, plr.plr->Trade, sizeof(plr.plr->Trade));
|
||||
|
||||
sock->sendPacket((void*)&resp2, P_FE2CL_REP_PC_TRADE_CONFIRM_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_SUCC));
|
||||
|
||||
plr2.plr->money = plr2.plr->money + plr.plr->moneyInTrade - plr2.plr->moneyInTrade;
|
||||
resp2.iCandy = plr2.plr->money;
|
||||
|
||||
memcpy(resp2.Item, plr.plr->Trade, sizeof(plr.plr->Trade));
|
||||
memcpy(resp2.ItemStay, plr2.plr->Trade, sizeof(plr2.plr->Trade));
|
||||
|
||||
otherSock->sendPacket((void*)&resp2, P_FE2CL_REP_PC_TRADE_CONFIRM_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_SUCC));
|
||||
} else {
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
plr.plr->isTradeConfirm = true;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM));
|
||||
}
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeConfirmCancelHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL* pacdat = (sP_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
PlayerView& plr2 = PlayerManager::players[otherSock];
|
||||
|
||||
plr.plr->isTrading = false;
|
||||
plr.plr->isTradeConfirm = false;
|
||||
plr2.plr->isTrading = false;
|
||||
plr2.plr->isTradeConfirm = false;
|
||||
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL));
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeRegisterItemHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_ITEM_REGISTER))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TRADE_ITEM_REGISTER* pacdat = (sP_CL2FE_REQ_PC_TRADE_ITEM_REGISTER*)data->buf;
|
||||
|
||||
if (pacdat->Item.iSlotNum < 0 || pacdat->Item.iSlotNum > 4)
|
||||
return; // sanity check
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
resp.TradeItem = pacdat->Item;
|
||||
resp.InvenItem = pacdat->Item;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
plr.plr->Trade[pacdat->Item.iSlotNum] = pacdat->Item;
|
||||
plr.plr->isTradeConfirm = false;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC));
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeUnregisterItemHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER* pacdat = (sP_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
resp.TradeItem = pacdat->Item;
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
resp.InvenItem = plr.plr->Trade[pacdat->Item.iSlotNum];
|
||||
plr.plr->isTradeConfirm = false;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
int temp_num = pacdat->Item.iSlotNum;
|
||||
|
||||
if (temp_num >= 0 && temp_num <= 4) {
|
||||
plr.plr->Trade[temp_num].iID = 0;
|
||||
plr.plr->Trade[temp_num].iType = 0;
|
||||
plr.plr->Trade[temp_num].iOpt = 0;
|
||||
plr.plr->Trade[temp_num].iInvenNum = 0;
|
||||
plr.plr->Trade[temp_num].iSlotNum = 0;
|
||||
}
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC));
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeRegisterCashHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_CASH_REGISTER))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TRADE_CASH_REGISTER* pacdat = (sP_CL2FE_REQ_PC_TRADE_CASH_REGISTER*)data->buf;
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
|
||||
if (pacdat->iCandy < 0 || pacdat->iCandy > plr.plr->money)
|
||||
return; // famous glitch, begone
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
resp.iCandy = pacdat->iCandy;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
plr.plr->moneyInTrade = pacdat->iCandy;
|
||||
plr.plr->isTradeConfirm = false;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC));
|
||||
}
|
||||
|
||||
void ItemManager::itemTradeChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT))
|
||||
return; // malformed packet
|
||||
sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT* pacdat = (sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT*)data->buf;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT, resp);
|
||||
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
|
||||
memcpy(resp.szFreeChat, pacdat->szFreeChat, sizeof(pacdat->szFreeChat));
|
||||
|
||||
resp.iEmoteCode = pacdat->iEmoteCode;
|
||||
|
||||
int iID_Check;
|
||||
|
||||
if (pacdat->iID_Request == pacdat->iID_From) {
|
||||
iID_Check = pacdat->iID_To;
|
||||
} else {
|
||||
iID_Check = pacdat->iID_From;
|
||||
}
|
||||
|
||||
CNSocket* otherSock = sock;
|
||||
|
||||
for (auto pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == iID_Check) {
|
||||
otherSock = pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT));
|
||||
}
|
||||
|
||||
void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_CHEST_OPEN))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_ITEM_CHEST_OPEN *pkt = (sP_CL2FE_REQ_ITEM_CHEST_OPEN *)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// item giving packet
|
||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||
assert(resplen < CN_PACKET_BUFFER_SIZE);
|
||||
// we know it's only one trailing struct, so we can skip full validation
|
||||
|
||||
uint8_t respbuf[resplen]; // not a variable length array, don't worry
|
||||
sP_FE2CL_REP_REWARD_ITEM *reward = (sP_FE2CL_REP_REWARD_ITEM *)respbuf;
|
||||
sItemReward *item = (sItemReward *)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
||||
|
||||
// don't forget to zero the buffer!
|
||||
memset(respbuf, 0, resplen);
|
||||
|
||||
// simple rewards
|
||||
reward->iFatigue = 100; // prevents warning message
|
||||
reward->iFatigue_Level = 1;
|
||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||
|
||||
// item reward
|
||||
item->sItem.iType = 0;
|
||||
item->sItem.iID = 96;
|
||||
item->iSlotNum = pkt->iSlotNum;
|
||||
item->eIL = pkt->eIL;
|
||||
|
||||
// update player
|
||||
plr->Inven[pkt->iSlotNum] = item->sItem;
|
||||
|
||||
// transmit item
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||
|
||||
// chest opening acknowledgement packet
|
||||
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
||||
|
||||
resp.iSlotNum = pkt->iSlotNum;
|
||||
|
||||
std::cout << "opening chest..." << std::endl;
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, sizeof(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC));
|
||||
}
|
||||
|
||||
// TODO: use this in cleaned up ItemManager
|
||||
int ItemManager::findFreeSlot(Player *plr) {
|
||||
int i;
|
||||
sItemBase free;
|
||||
|
||||
memset((void*)&free, 0, sizeof(sItemBase));
|
||||
|
||||
for (i = 0; i < AINVEN_COUNT; i++)
|
||||
if (memcmp((void*)&plr->Inven[i], (void*)&free, sizeof(sItemBase)) == 0)
|
||||
return i;
|
||||
|
||||
// not found
|
||||
return -1;
|
||||
}
|
25
src/ItemManager.hpp
Normal file
25
src/ItemManager.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "CNShardServer.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
namespace ItemManager {
|
||||
void init();
|
||||
|
||||
void itemMoveHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemDeleteHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemGMGiveHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeOfferHandler(CNSocket* sock, CNPacketData* data);
|
||||
//void itemTradeOfferCancel(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeOfferAcceptHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeOfferRefusalHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeConfirmHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeConfirmCancelHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeRegisterItemHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeUnregisterItemHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeRegisterCashHandler(CNSocket* sock, CNPacketData* data);
|
||||
void itemTradeChatHandler(CNSocket* sock, CNPacketData* data);
|
||||
void chestOpenHandler(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
int findFreeSlot(Player *plr);
|
||||
}
|
55
src/MissionManager.cpp
Normal file
55
src/MissionManager.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "CNShardServer.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "MissionManager.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
|
||||
void MissionManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_START, acceptMission);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_END, completeMission);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID, setMission);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_STOP, quitMission);
|
||||
}
|
||||
|
||||
void MissionManager::acceptMission(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_START))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TASK_START* missionData = (sP_CL2FE_REQ_PC_TASK_START*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_START_SUCC, response);
|
||||
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_START_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_START_SUCC));
|
||||
}
|
||||
|
||||
void MissionManager::completeMission(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_END))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TASK_END* missionData = (sP_CL2FE_REQ_PC_TASK_END*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
|
||||
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
||||
}
|
||||
|
||||
void MissionManager::setMission(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID* missionData = (sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, response);
|
||||
|
||||
response.iCurrentMissionID = missionData->iCurrentMissionID;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, sizeof(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID));
|
||||
}
|
||||
|
||||
void MissionManager::quitMission(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_STOP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TASK_STOP* missionData = (sP_CL2FE_REQ_PC_TASK_STOP*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_STOP_SUCC, response);
|
||||
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_STOP_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_STOP_SUCC));
|
||||
}
|
12
src/MissionManager.hpp
Normal file
12
src/MissionManager.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "CNShardServer.hpp"
|
||||
|
||||
namespace MissionManager {
|
||||
void init();
|
||||
|
||||
void acceptMission(CNSocket* sock, CNPacketData* data);
|
||||
void completeMission(CNSocket* sock, CNPacketData* data);
|
||||
void setMission(CNSocket* sock, CNPacketData* data);
|
||||
void quitMission(CNSocket* sock, CNPacketData* data);
|
||||
}
|
37
src/NPC.hpp
Normal file
37
src/NPC.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "CNStructs.hpp"
|
||||
|
||||
class BaseNPC {
|
||||
public:
|
||||
sNPCAppearanceData appearanceData;
|
||||
|
||||
BaseNPC() {};
|
||||
BaseNPC(int x, int y, int z, int type) {
|
||||
appearanceData.iX = x;
|
||||
appearanceData.iY = y;
|
||||
appearanceData.iZ = z;
|
||||
appearanceData.iNPCType = type;
|
||||
appearanceData.iHP = 400;
|
||||
appearanceData.iAngle = 0;
|
||||
appearanceData.iConditionBitFlag = 0;
|
||||
appearanceData.iBarkerType = 0;
|
||||
|
||||
// hopefully no collisions happen :eyes:
|
||||
appearanceData.iNPC_ID = (int32_t)rand();
|
||||
};
|
||||
|
||||
BaseNPC(int x, int y, int z, int type, int hp, int cond, int angle, int barker) {
|
||||
appearanceData.iX = x;
|
||||
appearanceData.iY = y;
|
||||
appearanceData.iZ = z;
|
||||
appearanceData.iNPCType = type;
|
||||
appearanceData.iHP = hp;
|
||||
appearanceData.iAngle = angle;
|
||||
appearanceData.iConditionBitFlag = cond;
|
||||
appearanceData.iBarkerType = barker;
|
||||
|
||||
// hopefully no collisions happen :eyes:
|
||||
appearanceData.iNPC_ID = (int32_t)rand();
|
||||
}
|
||||
};
|
193
src/NPCManager.cpp
Normal file
193
src/NPCManager.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
#include "NPCManager.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "contrib/JSON.hpp"
|
||||
|
||||
std::map<int32_t, BaseNPC> NPCManager::NPCs;
|
||||
std::map<int32_t, WarpLocation> NPCManager::Warps;
|
||||
std::vector<WarpLocation> NPCManager::RespawnPoints;
|
||||
|
||||
void NPCManager::init() {
|
||||
// load NPCs from NPCs.json into our NPC manager
|
||||
// Temporary fix, IDs will be pulled from json later
|
||||
int i = 0;
|
||||
|
||||
try {
|
||||
std::ifstream inFile(settings::NPCJSON);
|
||||
nlohmann::json npcData;
|
||||
|
||||
// read file into json
|
||||
inFile >> npcData;
|
||||
|
||||
for (nlohmann::json::iterator npc = npcData.begin(); npc != npcData.end(); npc++) {
|
||||
BaseNPC tmp(npc.value()["x"], npc.value()["y"], npc.value()["z"], npc.value()["id"]);
|
||||
|
||||
// Temporary fix, IDs will be pulled from json later
|
||||
tmp.appearanceData.iNPC_ID = i;
|
||||
i++;
|
||||
|
||||
NPCs[tmp.appearanceData.iNPC_ID] = tmp;
|
||||
|
||||
if (npc.value()["id"] == 641 || npc.value()["id"] == 642)
|
||||
RespawnPoints.push_back({ npc.value()["x"], npc.value()["y"], ((int)npc.value()["z"]) + RESURRECT_HEIGHT });
|
||||
}
|
||||
|
||||
}
|
||||
catch (const std::exception& err) {
|
||||
std::cerr << "[WARN] Malformed NPCs.json file! Reason:" << err.what() << std::endl;
|
||||
}
|
||||
|
||||
// load temporary mob dump
|
||||
try {
|
||||
std::ifstream inFile(settings::MOBJSON); // not in settings, since it's temp
|
||||
nlohmann::json npcData;
|
||||
|
||||
// read file into json
|
||||
inFile >> npcData;
|
||||
|
||||
for (nlohmann::json::iterator npc = npcData.begin(); npc != npcData.end(); npc++) {
|
||||
BaseNPC tmp(npc.value()["iX"], npc.value()["iY"], npc.value()["iZ"], npc.value()["iNPCType"],
|
||||
npc.value()["iHP"], npc.value()["iConditionBitFlag"], npc.value()["iAngle"], npc.value()["iBarkerType"]);
|
||||
|
||||
// Temporary fix, IDs will be pulled from json later
|
||||
tmp.appearanceData.iNPC_ID = i;
|
||||
i++;
|
||||
|
||||
NPCs[tmp.appearanceData.iNPC_ID] = tmp;
|
||||
}
|
||||
|
||||
std::cout << "[INFO] populated " << NPCs.size() << " NPCs" << std::endl;
|
||||
}
|
||||
catch (const std::exception& err) {
|
||||
std::cerr << "[WARN] Malformed mobs.json file! Reason:" << err.what() << std::endl;
|
||||
}
|
||||
|
||||
try {
|
||||
std::ifstream infile(settings::WARPJSON);
|
||||
nlohmann::json warpData;
|
||||
|
||||
// read file into json
|
||||
infile >> warpData;
|
||||
|
||||
for (nlohmann::json::iterator warp = warpData.begin(); warp != warpData.end(); warp++) {
|
||||
WarpLocation warpLoc = { warp.value()["m_iToX"], warp.value()["m_iToY"], warp.value()["m_iToZ"] };
|
||||
int warpID = atoi(warp.key().c_str());
|
||||
Warps[warpID] = warpLoc;
|
||||
}
|
||||
|
||||
std::cout << "[INFO] populated " << Warps.size() << " Warps" << std::endl;
|
||||
}
|
||||
catch (const std::exception& err) {
|
||||
std::cerr << "[WARN] Malformed warps.json file! Reason:" << err.what() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_NPC, npcWarpHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_SUMMON, npcSummonHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_BARKER, npcBarkHandler);
|
||||
}
|
||||
|
||||
void NPCManager::updatePlayerNPCS(CNSocket* sock, PlayerView& view) {
|
||||
std::list<int32_t> yesView;
|
||||
std::list<int32_t> noView;
|
||||
|
||||
for (auto& pair : NPCs) {
|
||||
int diffX = abs(view.plr->x - pair.second.appearanceData.iX);
|
||||
int diffY = abs(view.plr->y - pair.second.appearanceData.iY);
|
||||
|
||||
if (diffX < settings::NPCDISTANCE && diffY < settings::NPCDISTANCE) {
|
||||
yesView.push_back(pair.first);
|
||||
}
|
||||
else {
|
||||
noView.push_back(pair.first);
|
||||
}
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
|
||||
std::list<int32_t>::iterator i = view.viewableNPCs.begin();
|
||||
while (i != view.viewableNPCs.end()) {
|
||||
int32_t id = *i;
|
||||
|
||||
if (std::find(noView.begin(), noView.end(), id) != noView.end()) {
|
||||
// it shouldn't be visible, send NPC_EXIT
|
||||
|
||||
exitData.iNPC_ID = id;
|
||||
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
|
||||
|
||||
// remove from view
|
||||
view.viewableNPCs.erase(i++);
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
|
||||
for (int32_t id : yesView) {
|
||||
if (std::find(view.viewableNPCs.begin(), view.viewableNPCs.end(), id) == view.viewableNPCs.end()) {
|
||||
// needs to be added to viewableNPCs! send NPC_ENTER
|
||||
|
||||
enterData.NPCAppearanceData = NPCs[id].appearanceData;
|
||||
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
|
||||
|
||||
// add to viewable
|
||||
view.viewableNPCs.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
PlayerManager::players[sock].viewableNPCs = view.viewableNPCs;
|
||||
}
|
||||
|
||||
void NPCManager::npcBarkHandler(CNSocket* sock, CNPacketData* data) {} // stubbed for now
|
||||
|
||||
void NPCManager::npcSummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NPC_SUMMON))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NPC_SUMMON* req = (sP_CL2FE_REQ_NPC_SUMMON*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_NPC_ENTER, resp);
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// permission & sanity check
|
||||
if (!plr->IsGM || req->iNPCType >= 3314)
|
||||
return;
|
||||
|
||||
resp.NPCAppearanceData.iNPC_ID = rand(); // cpunch-style
|
||||
resp.NPCAppearanceData.iNPCType = req->iNPCType;
|
||||
resp.NPCAppearanceData.iHP = 1000; // TODO: placeholder
|
||||
resp.NPCAppearanceData.iX = plr->x;
|
||||
resp.NPCAppearanceData.iY = plr->y;
|
||||
resp.NPCAppearanceData.iZ = plr->z;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
|
||||
}
|
||||
|
||||
void NPCManager::npcWarpHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_WARP_USE_NPC))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_WARP_USE_NPC* warpNpc = (sP_CL2FE_REQ_PC_WARP_USE_NPC*)data->buf;
|
||||
PlayerView& plrv = PlayerManager::players[sock];
|
||||
|
||||
// sanity check
|
||||
if (Warps.find(warpNpc->iWarpID) == Warps.end())
|
||||
return;
|
||||
|
||||
// send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC, resp);
|
||||
resp.iX = Warps[warpNpc->iWarpID].x;
|
||||
resp.iY = Warps[warpNpc->iWarpID].y;
|
||||
resp.iZ = Warps[warpNpc->iWarpID].z;
|
||||
|
||||
// force player & NPC reload
|
||||
plrv.viewable.clear();
|
||||
plrv.viewableNPCs.clear();
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC));
|
||||
}
|
28
src/NPCManager.hpp
Normal file
28
src/NPCManager.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "CNProtocol.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "NPC.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#define RESURRECT_HEIGHT 400
|
||||
|
||||
// this should really be called vec3 or something...
|
||||
struct WarpLocation {
|
||||
int x, y, z;
|
||||
};
|
||||
|
||||
namespace NPCManager {
|
||||
extern std::map<int32_t, BaseNPC> NPCs;
|
||||
extern std::map<int32_t, WarpLocation> Warps;
|
||||
extern std::vector<WarpLocation> RespawnPoints;
|
||||
void init();
|
||||
|
||||
void npcBarkHandler(CNSocket* sock, CNPacketData* data);
|
||||
void npcSummonHandler(CNSocket* sock, CNPacketData* data);
|
||||
void npcWarpHandler(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void updatePlayerNPCS(CNSocket* sock, PlayerView& plr);
|
||||
}
|
210
src/NanoManager.cpp
Normal file
210
src/NanoManager.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
#include "CNShardServer.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "NanoManager.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
|
||||
void NanoManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_EQUIP, nanoEquipHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_UNEQUIP, nanoUnEquipHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_NANO, nanoGMGiveHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_TUNE, nanoSkillSetHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_SKILL_USE, nanoSkillUseHandler);
|
||||
}
|
||||
|
||||
void NanoManager::nanoEquipHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_EQUIP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_EQUIP* nano = (sP_CL2FE_REQ_NANO_EQUIP*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_EQUIP_SUCC, resp);
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity check
|
||||
if (nano->iNanoSlotNum > 2 || nano->iNanoSlotNum < 0)
|
||||
return;
|
||||
|
||||
resp.iNanoID = nano->iNanoID;
|
||||
resp.iNanoSlotNum = nano->iNanoSlotNum;
|
||||
|
||||
// Update player
|
||||
plr->equippedNanos[nano->iNanoSlotNum] = nano->iNanoID;
|
||||
|
||||
// unsummon nano if replaced
|
||||
if (plr->activeNano == plr->equippedNanos[nano->iNanoSlotNum])
|
||||
summonNano(sock, -1);
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_EQUIP_SUCC, sizeof(sP_FE2CL_REP_NANO_EQUIP_SUCC));
|
||||
}
|
||||
|
||||
void NanoManager::nanoUnEquipHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_UNEQUIP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_UNEQUIP* nano = (sP_CL2FE_REQ_NANO_UNEQUIP*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_UNEQUIP_SUCC, resp);
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity check
|
||||
if (nano->iNanoSlotNum > 2 || nano->iNanoSlotNum < 0)
|
||||
return;
|
||||
|
||||
resp.iNanoSlotNum = nano->iNanoSlotNum;
|
||||
|
||||
// unsummon nano if removed
|
||||
if (plr->equippedNanos[nano->iNanoSlotNum] == plr->activeNano)
|
||||
summonNano(sock, -1);
|
||||
|
||||
// update player
|
||||
plr->equippedNanos[nano->iNanoSlotNum] = 0;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_UNEQUIP_SUCC, sizeof(sP_FE2CL_REP_NANO_UNEQUIP_SUCC));
|
||||
}
|
||||
|
||||
void NanoManager::nanoGMGiveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_NANO))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
// Cmd: /nano <nanoId>
|
||||
sP_CL2FE_REQ_PC_GIVE_NANO* nano = (sP_CL2FE_REQ_PC_GIVE_NANO*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// Add nano to player
|
||||
addNano(sock, nano->iNanoID, 0);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to add nano id: " << nano->iNanoID << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_ACTIVE))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_ACTIVE* pkt = (sP_CL2FE_REQ_NANO_ACTIVE*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
summonNano(sock, pkt->iNanoSlotNum);
|
||||
|
||||
// Send to client
|
||||
DEBUGLOG(
|
||||
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_SKILL_USE))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_SKILL_USE* skill = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// Send to client
|
||||
INITSTRUCT(sP_FE2CL_NANO_SKILL_USE_SUCC, resp);
|
||||
resp.iArg1 = skill->iArg1;
|
||||
resp.iArg2 = skill->iArg2;
|
||||
resp.iArg3 = skill->iArg3;
|
||||
resp.iBulletID = skill->iBulletID;
|
||||
resp.iTargetCnt = skill->iTargetCnt;
|
||||
resp.iPC_ID = plr->iID;
|
||||
resp.iNanoStamina = 150; // Hardcoded for now
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_NANO_SKILL_USE_SUCC, sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC));
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to summon nano skill " << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
void NanoManager::nanoSkillSetHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_TUNE))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_TUNE* skill = (sP_CL2FE_REQ_NANO_TUNE*)data->buf;
|
||||
setNanoSkill(sock, skill->iNanoID, skill->iTuneID);
|
||||
}
|
||||
|
||||
#pragma region Helper methods
|
||||
void NanoManager::addNano(CNSocket* sock, int16_t nanoId, int16_t slot) {
|
||||
if (nanoId > 36)
|
||||
return;
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// Send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_NANO_CREATE_SUCC, resp);
|
||||
resp.Nano.iID = nanoId;
|
||||
resp.Nano.iStamina = 150;
|
||||
resp.iQuestItemSlotNum = slot;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_NANO_CREATE_SUCC, sizeof(sP_FE2CL_REP_PC_NANO_CREATE_SUCC));
|
||||
|
||||
// Update player
|
||||
plr->Nanos[nanoId] = resp.Nano;
|
||||
}
|
||||
|
||||
void NanoManager::summonNano(CNSocket *sock, int slot) {
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_ACTIVE_SUCC, resp);
|
||||
resp.iActiveNanoSlotNum = slot;
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_ACTIVE_SUCC, sizeof(sP_FE2CL_REP_NANO_ACTIVE_SUCC));
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
std::cout << "summon nano\n";
|
||||
|
||||
if (slot > 2 || slot < 0)
|
||||
return; //sanity check
|
||||
|
||||
int nanoId = plr->equippedNanos[slot];
|
||||
|
||||
if (nanoId > 36 || nanoId < 0)
|
||||
return; // sanity check
|
||||
|
||||
sNano nano = plr->Nanos[nanoId];
|
||||
|
||||
// Send to other players
|
||||
INITSTRUCT(sP_FE2CL_NANO_ACTIVE, pkt1);
|
||||
|
||||
pkt1.iPC_ID = plr->iID;
|
||||
pkt1.Nano = nano;
|
||||
|
||||
for (CNSocket* s : PlayerManager::players[sock].viewable)
|
||||
s->sendPacket((void*)&pkt1, P_FE2CL_NANO_ACTIVE, sizeof(sP_FE2CL_NANO_ACTIVE));
|
||||
|
||||
// update player
|
||||
plr->activeNano = nanoId;
|
||||
}
|
||||
|
||||
void NanoManager::setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId) {
|
||||
if (nanoId > 36)
|
||||
return;
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
sNano nano = plr->Nanos[nanoId];
|
||||
|
||||
nano.iSkillID = skillId;
|
||||
plr->Nanos[nanoId] = nano;
|
||||
|
||||
// Send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_TUNE_SUCC, resp);
|
||||
resp.iNanoID = nanoId;
|
||||
resp.iSkillID = skillId;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_TUNE_SUCC, sizeof(sP_FE2CL_REP_NANO_TUNE_SUCC));
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " set skill id " << skillId << " for nano: " << nanoId << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
void NanoManager::resetNanoSkill(CNSocket* sock, int16_t nanoId) {
|
||||
if (nanoId > 36)
|
||||
return;
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
sNano nano = plr->Nanos[nanoId];
|
||||
|
||||
// 0 is reset
|
||||
nano.iSkillID = 0;
|
||||
plr->Nanos[nanoId] = nano;
|
||||
}
|
||||
#pragma endregion
|
19
src/NanoManager.hpp
Normal file
19
src/NanoManager.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "CNShardServer.hpp"
|
||||
|
||||
namespace NanoManager {
|
||||
void init();
|
||||
void nanoSummonHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoEquipHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoUnEquipHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoGMGiveHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoSkillSetHandler(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
// Helper methods
|
||||
void addNano(CNSocket* sock, int16_t nanoId, int16_t slot);
|
||||
void summonNano(CNSocket* sock, int slot);
|
||||
void setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId);
|
||||
void resetNanoSkill(CNSocket* sock, int16_t nanoId);
|
||||
}
|
@@ -1,25 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#ifndef _PLR_HPP
|
||||
#define _PLR_HPP
|
||||
|
||||
#include "CNProtocol.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
|
||||
struct Player {
|
||||
int accountId;
|
||||
int64_t SerialKey;
|
||||
int32_t iID;
|
||||
uint64_t FEKey;
|
||||
|
||||
int level;
|
||||
int HP;
|
||||
int slot;
|
||||
int slot; // player slot, not nano slot
|
||||
int32_t money;
|
||||
int32_t fusionmatter;
|
||||
sPCStyle PCStyle;
|
||||
sPCStyle2 PCStyle2;
|
||||
sNano Nanos[37]; // acquired nanos
|
||||
int equippedNanos[3];
|
||||
int activeNano; // active nano (index into Nanos)
|
||||
int8_t iPCState;
|
||||
|
||||
int x, y, z, angle;
|
||||
sItemBase Equip[AEQUIP_COUNT];
|
||||
sItemBase Inven[AINVEN_COUNT];
|
||||
sItemTrade Trade[12];
|
||||
int32_t moneyInTrade;
|
||||
bool isTrading;
|
||||
bool isTradeConfirm;
|
||||
bool IsGM;
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,5 +1,6 @@
|
||||
#include "CNProtocol.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "NPCManager.hpp"
|
||||
#include "CNShardServer.hpp"
|
||||
#include "CNShared.hpp"
|
||||
|
||||
@@ -18,15 +19,34 @@ void PlayerManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVE, PlayerManager::movePlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_STOP, PlayerManager::stopPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_JUMP, PlayerManager::jumpPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_JUMPPAD, PlayerManager::jumppadPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_LAUNCHER, PlayerManager::launchPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ZIPLINE, PlayerManager::ziplinePlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVEPLATFORM, PlayerManager::movePlatformPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SLOPE, PlayerManager::moveSlopePlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GOTO, PlayerManager::gotoPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SET_VALUE, PlayerManager::setSpecialPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REP_LIVE_CHECK, PlayerManager::heartbeatPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_REGEN, PlayerManager::revivePlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EXIT, PlayerManager::exitGame);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH, PlayerManager::setSpecialSwitchPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_ON, PlayerManager::enterPlayerVehicle);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_OFF, PlayerManager::exitPlayerVehicle);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_CHANGE_MENTOR, PlayerManager::changePlayerGuide);
|
||||
}
|
||||
|
||||
void PlayerManager::addPlayer(CNSocket* key, Player plr) {
|
||||
Player *p = new Player();
|
||||
|
||||
memcpy(p, &plr, sizeof(Player));
|
||||
|
||||
players[key] = PlayerView();
|
||||
players[key].viewable = std::list<CNSocket*>();
|
||||
players[key].plr = plr;
|
||||
players[key].plr = p;
|
||||
players[key].lastHeartbeat = 0;
|
||||
|
||||
std::cout << U16toU8(plr.PCStyle.szFirstName) << " " << U16toU8(plr.PCStyle.szLastName) << " has joined!" << std::endl;
|
||||
std::cout << players.size() << " players" << std::endl;
|
||||
}
|
||||
|
||||
void PlayerManager::removePlayer(CNSocket* key) {
|
||||
@@ -36,24 +56,24 @@ void PlayerManager::removePlayer(CNSocket* key) {
|
||||
for (CNSocket* otherSock : players[key].viewable) {
|
||||
players[otherSock].viewable.remove(key); // gone
|
||||
|
||||
// now sent PC_EXIT packet
|
||||
sP_FE2CL_PC_EXIT* exitPacket = (sP_FE2CL_PC_EXIT*)xmalloc(sizeof(sP_FE2CL_PC_EXIT));
|
||||
exitPacket->iID = players[key].plr.iID;
|
||||
// now send PC_EXIT packet
|
||||
sP_FE2CL_PC_EXIT exitPacket;
|
||||
exitPacket.iID = players[key].plr->iID;
|
||||
|
||||
otherSock->sendPacket(new CNPacketData((void*)exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT), otherSock->getFEKey()));
|
||||
otherSock->sendPacket((void*)&exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT));
|
||||
}
|
||||
|
||||
std::cout << U16toU8(cachedView.plr->PCStyle.szFirstName) << " " << U16toU8(cachedView.plr->PCStyle.szLastName) << " has left!" << std::endl;
|
||||
std::cout << players.size() << " players" << std::endl;
|
||||
|
||||
delete cachedView.plr;
|
||||
players.erase(key);
|
||||
}
|
||||
|
||||
Player PlayerManager::getPlayer(CNSocket* key) {
|
||||
return players[key].plr;
|
||||
}
|
||||
|
||||
void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
|
||||
players[sock].plr.x = X;
|
||||
players[sock].plr.y = Y;
|
||||
players[sock].plr.z = Z;
|
||||
players[sock].plr->x = X;
|
||||
players[sock].plr->y = Y;
|
||||
players[sock].plr->z = Z;
|
||||
|
||||
std::vector<CNSocket*> noView;
|
||||
std::vector<CNSocket*> yesView;
|
||||
@@ -63,82 +83,103 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) {
|
||||
if (pair.first == sock)
|
||||
continue; // ignore our own connection
|
||||
|
||||
int diffX = abs(pair.second.plr.x - X); // the map is like a grid, X and Y are your position on the map, Z is the height. very different from other games...
|
||||
int diffY = abs(pair.second.plr.y - Y);
|
||||
int diffX = abs(pair.second.plr->x - X); // the map is like a grid, X and Y are your position on the map, Z is the height. very different from other games...
|
||||
int diffY = abs(pair.second.plr->y - Y);
|
||||
|
||||
double dist = sqrt(pow(diffX, 2) + pow(diffY, 2));
|
||||
|
||||
if (dist > settings::VIEWDISTANCE) {
|
||||
noView.push_back(pair.first);
|
||||
} else {
|
||||
if (diffX < settings::PLAYERDISTANCE && diffY < settings::PLAYERDISTANCE) {
|
||||
yesView.push_back(pair.first);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<CNSocket*> cachedview(players[sock].viewable); // copies the viewable
|
||||
|
||||
for (CNSocket* otherSock : cachedview) {
|
||||
if (std::find(noView.begin(), noView.end(), otherSock) != noView.end()) {
|
||||
// sock shouldn't be visible, send PC_EXIT packet & remove them
|
||||
|
||||
sP_FE2CL_PC_EXIT* exitPacket = (sP_FE2CL_PC_EXIT*)xmalloc(sizeof(sP_FE2CL_PC_EXIT));
|
||||
sP_FE2CL_PC_EXIT* exitPacketOther = (sP_FE2CL_PC_EXIT*)xmalloc(sizeof(sP_FE2CL_PC_EXIT));
|
||||
|
||||
exitPacket->iID = players[sock].plr.iID;
|
||||
exitPacketOther->iID = players[otherSock].plr.iID;
|
||||
|
||||
otherSock->sendPacket(new CNPacketData((void*)exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT), otherSock->getFEKey()));
|
||||
sock->sendPacket(new CNPacketData((void*)exitPacketOther, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT), sock->getFEKey()));
|
||||
|
||||
players[sock].viewable.remove(otherSock);
|
||||
players[otherSock].viewable.remove(sock);
|
||||
else {
|
||||
noView.push_back(pair.first);
|
||||
}
|
||||
}
|
||||
|
||||
cachedview = players[sock].viewable;
|
||||
INITSTRUCT(sP_FE2CL_PC_EXIT, exitPacket);
|
||||
std::list<CNSocket*>::iterator i = players[sock].viewable.begin();
|
||||
while (i != players[sock].viewable.end()) {
|
||||
CNSocket* otherSock = *i;
|
||||
if (std::find(noView.begin(), noView.end(), otherSock) != noView.end()) {
|
||||
|
||||
// sock shouldn't be visible, send PC_EXIT packet
|
||||
exitPacket.iID = players[sock].plr->iID;
|
||||
otherSock->sendPacket((void*)&exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT));
|
||||
exitPacket.iID = players[otherSock].plr->iID;
|
||||
sock->sendPacket((void*)&exitPacket, P_FE2CL_PC_EXIT, sizeof(sP_FE2CL_PC_EXIT));
|
||||
|
||||
// remove them from the viewable list
|
||||
players[sock].viewable.erase(i++);
|
||||
players[otherSock].viewable.remove(sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_NEW, newPlayer);
|
||||
for (CNSocket* otherSock : yesView) {
|
||||
if (std::find(cachedview.begin(), cachedview.end(), otherSock) == cachedview.end()) {
|
||||
if (std::find(players[sock].viewable.begin(), players[sock].viewable.end(), otherSock) == players[sock].viewable.end()) {
|
||||
// this needs to be added to the viewable players, send PC_ENTER
|
||||
|
||||
sP_FE2CL_PC_NEW* newPlayer = (sP_FE2CL_PC_NEW*)xmalloc(sizeof(sP_FE2CL_PC_NEW)); // current connection to other player
|
||||
sP_FE2CL_PC_NEW* newOtherPlayer = (sP_FE2CL_PC_NEW*)xmalloc(sizeof(sP_FE2CL_PC_NEW)); // other player to current connection
|
||||
Player *otherPlr = players[otherSock].plr;
|
||||
Player *plr = players[sock].plr;
|
||||
|
||||
Player otherPlr = players[otherSock].plr;
|
||||
Player plr = players[sock].plr;
|
||||
newPlayer.PCAppearanceData.iID = plr->iID;
|
||||
newPlayer.PCAppearanceData.iHP = plr->HP;
|
||||
newPlayer.PCAppearanceData.iLv = plr->level;
|
||||
newPlayer.PCAppearanceData.iX = plr->x;
|
||||
newPlayer.PCAppearanceData.iY = plr->y;
|
||||
newPlayer.PCAppearanceData.iZ = plr->z;
|
||||
newPlayer.PCAppearanceData.iAngle = plr->angle;
|
||||
newPlayer.PCAppearanceData.PCStyle = plr->PCStyle;
|
||||
newPlayer.PCAppearanceData.Nano = plr->Nanos[plr->activeNano];
|
||||
newPlayer.PCAppearanceData.iPCState = plr->iPCState;
|
||||
memcpy(newPlayer.PCAppearanceData.ItemEquip, plr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
||||
|
||||
newPlayer->PCAppearanceData.iID = plr.iID;
|
||||
newPlayer->PCAppearanceData.iHP = plr.HP;
|
||||
newPlayer->PCAppearanceData.iLv = plr.level;
|
||||
newPlayer->PCAppearanceData.iX = plr.x;
|
||||
newPlayer->PCAppearanceData.iY = plr.y;
|
||||
newPlayer->PCAppearanceData.iZ = plr.z;
|
||||
newPlayer->PCAppearanceData.iAngle = plr.angle;
|
||||
newPlayer->PCAppearanceData.PCStyle = plr.PCStyle;
|
||||
memcpy(newPlayer->PCAppearanceData.ItemEquip, plr.Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
||||
otherSock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
|
||||
|
||||
newOtherPlayer->PCAppearanceData.iID = otherPlr.iID;
|
||||
newOtherPlayer->PCAppearanceData.iHP = otherPlr.HP;
|
||||
newOtherPlayer->PCAppearanceData.iLv = otherPlr.level;
|
||||
newOtherPlayer->PCAppearanceData.iX = otherPlr.x;
|
||||
newOtherPlayer->PCAppearanceData.iY = otherPlr.y;
|
||||
newOtherPlayer->PCAppearanceData.iZ = otherPlr.z;
|
||||
newOtherPlayer->PCAppearanceData.iAngle = otherPlr.angle;
|
||||
newOtherPlayer->PCAppearanceData.PCStyle = otherPlr.PCStyle;
|
||||
memcpy(newOtherPlayer->PCAppearanceData.ItemEquip, otherPlr.Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
||||
newPlayer.PCAppearanceData.iID = otherPlr->iID;
|
||||
newPlayer.PCAppearanceData.iHP = otherPlr->HP;
|
||||
newPlayer.PCAppearanceData.iLv = otherPlr->level;
|
||||
newPlayer.PCAppearanceData.iX = otherPlr->x;
|
||||
newPlayer.PCAppearanceData.iY = otherPlr->y;
|
||||
newPlayer.PCAppearanceData.iZ = otherPlr->z;
|
||||
newPlayer.PCAppearanceData.iAngle = otherPlr->angle;
|
||||
newPlayer.PCAppearanceData.PCStyle = otherPlr->PCStyle;
|
||||
newPlayer.PCAppearanceData.Nano = otherPlr->Nanos[otherPlr->activeNano];
|
||||
newPlayer.PCAppearanceData.iPCState = otherPlr->iPCState;
|
||||
memcpy(newPlayer.PCAppearanceData.ItemEquip, otherPlr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)newOtherPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW), sock->getFEKey()));
|
||||
otherSock->sendPacket(new CNPacketData((void*)newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW), otherSock->getFEKey()));
|
||||
sock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
|
||||
|
||||
players[sock].viewable.push_back(otherSock);
|
||||
players[otherSock].viewable.push_back(sock);
|
||||
}
|
||||
}
|
||||
|
||||
NPCManager::updatePlayerNPCS(sock, players[sock]);
|
||||
}
|
||||
|
||||
std::list<CNSocket*> PlayerManager::getNearbyPlayers(int x, int y, int dist) {
|
||||
std::list<CNSocket*> plrs;
|
||||
|
||||
for (auto pair : players) {
|
||||
int diffX = abs(pair.second.plr->x - x);
|
||||
int diffY = abs(pair.second.plr->x - x);
|
||||
|
||||
if (diffX < dist && diffY < dist)
|
||||
plrs.push_back(pair.first);
|
||||
}
|
||||
|
||||
return plrs;
|
||||
}
|
||||
|
||||
void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_ENTER))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_ENTER* enter = (sP_CL2FE_REQ_PC_ENTER*)data->buf;
|
||||
sP_FE2CL_REP_PC_ENTER_SUCC* response = (sP_FE2CL_REP_PC_ENTER_SUCC*)xmalloc(sizeof(sP_FE2CL_REP_PC_ENTER_SUCC));
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_ENTER_SUCC, response);
|
||||
INITSTRUCT(sP_FE2CL_PC_MOTD_LOGIN, motd);
|
||||
|
||||
// TODO: check if serialkey exists, if it doesn't send sP_FE2CL_REP_PC_ENTER_FAIL
|
||||
Player plr = CNSharedData::getPlayer(enter->iEnterSerialKey);
|
||||
@@ -151,185 +192,342 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
std::cout << "\tPC_UID: " << plr.PCStyle.iPC_UID << std::endl;
|
||||
)
|
||||
|
||||
response->iID = rand();
|
||||
response->uiSvrTime = getTime();
|
||||
response->PCLoadData2CL.iUserLevel = 1;
|
||||
response->PCLoadData2CL.iHP = 1000 * plr.level;
|
||||
response->PCLoadData2CL.iLevel = plr.level;
|
||||
response->PCLoadData2CL.iMentor = 1;
|
||||
response->PCLoadData2CL.iMentorCount = 4;
|
||||
response->PCLoadData2CL.iMapNum = 0;
|
||||
response->PCLoadData2CL.iX = plr.x;
|
||||
response->PCLoadData2CL.iY = plr.y;
|
||||
response->PCLoadData2CL.iZ = plr.z;
|
||||
response->PCLoadData2CL.iActiveNanoSlotNum = -1;
|
||||
response->PCLoadData2CL.iFatigue = 50;
|
||||
response->PCLoadData2CL.PCStyle = plr.PCStyle;
|
||||
response->PCLoadData2CL.PCStyle2 = plr.PCStyle2;
|
||||
response.iID = rand();
|
||||
response.uiSvrTime = getTime();
|
||||
response.PCLoadData2CL.iUserLevel = 1;
|
||||
response.PCLoadData2CL.iHP = 3625; //TODO: Check player levelupdata and get this right
|
||||
response.PCLoadData2CL.iLevel = plr.level;
|
||||
response.PCLoadData2CL.iCandy = plr.money;
|
||||
response.PCLoadData2CL.iMentor = 1;
|
||||
response.PCLoadData2CL.iMentorCount = 4;
|
||||
response.PCLoadData2CL.iMapNum = 0;
|
||||
response.PCLoadData2CL.iX = plr.x;
|
||||
response.PCLoadData2CL.iY = plr.y;
|
||||
response.PCLoadData2CL.iZ = plr.z;
|
||||
response.PCLoadData2CL.iAngle = 130;
|
||||
response.PCLoadData2CL.iActiveNanoSlotNum = -1;
|
||||
response.PCLoadData2CL.iFatigue = 50;
|
||||
response.PCLoadData2CL.PCStyle = plr.PCStyle;
|
||||
response.PCLoadData2CL.PCStyle2 = plr.PCStyle2;
|
||||
|
||||
for (int i = 0; i < AEQUIP_COUNT; i++)
|
||||
response->PCLoadData2CL.aEquip[i] = plr.Equip[i];
|
||||
response.PCLoadData2CL.aEquip[i] = plr.Equip[i];
|
||||
|
||||
for (int i = 0; i < AINVEN_COUNT; i++)
|
||||
response.PCLoadData2CL.aInven[i] = plr.Inven[i];
|
||||
|
||||
// don't ask..
|
||||
for (int i = 1; i < 37; i++) {
|
||||
response->PCLoadData2CL.aNanoBank[i].iID = i;
|
||||
response->PCLoadData2CL.aNanoBank[i].iSkillID = 1;
|
||||
response->PCLoadData2CL.aNanoBank[i].iStamina = 150;
|
||||
response.PCLoadData2CL.aNanoBank[i].iID = i;
|
||||
response.PCLoadData2CL.aNanoBank[i].iSkillID = 1;
|
||||
response.PCLoadData2CL.aNanoBank[i].iStamina = 150;
|
||||
}
|
||||
|
||||
response->PCLoadData2CL.aNanoSlots[0] = 1;
|
||||
response->PCLoadData2CL.aNanoSlots[1] = 2;
|
||||
response->PCLoadData2CL.aNanoSlots[2] = 3;
|
||||
// temporarily not add nanos for nano add test through commands
|
||||
//response.PCLoadData2CL.aNanoSlots[0] = 1;
|
||||
//response.PCLoadData2CL.aNanoSlots[1] = 2;
|
||||
//response.PCLoadData2CL.aNanoSlots[2] = 3;
|
||||
|
||||
response->PCLoadData2CL.aQuestFlag[0] = -1;
|
||||
response.PCLoadData2CL.aQuestFlag[0] = -1;
|
||||
|
||||
plr.iID = response->iID;
|
||||
// shut computress up
|
||||
response.PCLoadData2CL.iFirstUseFlag1 = UINT64_MAX;
|
||||
response.PCLoadData2CL.iFirstUseFlag2 = UINT64_MAX;
|
||||
|
||||
plr.iID = response.iID;
|
||||
plr.SerialKey = enter->iEnterSerialKey;
|
||||
plr.HP = response->PCLoadData2CL.iHP;
|
||||
plr.HP = response.PCLoadData2CL.iHP;
|
||||
|
||||
sock->setEKey(CNSocketEncryption::createNewKey(response->uiSvrTime, response->iID + 1, response->PCLoadData2CL.iFusionMatter + 1));
|
||||
motd.iType = 1;
|
||||
U8toU16(settings::MOTDSTRING, (char16_t*)motd.szSystemMsg);
|
||||
|
||||
sock->setEKey(CNSocketEncryption::createNewKey(response.uiSvrTime, response.iID + 1, response.PCLoadData2CL.iFusionMatter + 1));
|
||||
sock->setFEKey(plr.FEKey);
|
||||
sock->setActiveKey(SOCKETKEY_FE); // send all packets using the FE key from now on
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_FE2CL_REP_PC_ENTER_SUCC, sizeof(sP_FE2CL_REP_PC_ENTER_SUCC), sock->getFEKey()));
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_ENTER_SUCC, sizeof(sP_FE2CL_REP_PC_ENTER_SUCC));
|
||||
|
||||
// transmit MOTD after entering the game, so the client hopefully changes modes on time
|
||||
sock->sendPacket((void*)&motd, P_FE2CL_PC_MOTD_LOGIN, sizeof(sP_FE2CL_PC_MOTD_LOGIN));
|
||||
|
||||
addPlayer(sock, plr);
|
||||
}
|
||||
|
||||
void PlayerManager::loadPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_LOADING_COMPLETE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_LOADING_COMPLETE* complete = (sP_CL2FE_REQ_PC_LOADING_COMPLETE*)data->buf;
|
||||
sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC* response = (sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC*)xmalloc(sizeof(sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC));
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC, response);
|
||||
Player *plr = getPlayer(sock);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2FE_REQ_PC_LOADING_COMPLETE:" << std::endl;
|
||||
std::cout << "\tPC_ID: " << complete->iPC_ID << std::endl;
|
||||
std::cout << "\tPC_ID: " << complete->iPC_ID << std::endl;
|
||||
)
|
||||
|
||||
response->iPC_ID = complete->iPC_ID;
|
||||
response.iPC_ID = complete->iPC_ID;
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC, sizeof(sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC), sock->getFEKey()));
|
||||
// reload players & NPCs
|
||||
updatePlayerPosition(sock, plr->x, plr->y, plr->z);
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC, sizeof(sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC));
|
||||
}
|
||||
|
||||
void PlayerManager::movePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_MOVE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_MOVE* moveData = (sP_CL2FE_REQ_PC_MOVE*)data->buf;
|
||||
updatePlayerPosition(sock, moveData->iX, moveData->iY, moveData->iZ);
|
||||
|
||||
players[sock].plr.angle = moveData->iAngle;
|
||||
players[sock].plr->angle = moveData->iAngle;
|
||||
uint64_t tm = getTime();
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_MOVE, moveResponse);
|
||||
|
||||
moveResponse.iID = players[sock].plr->iID;
|
||||
moveResponse.cKeyValue = moveData->cKeyValue;
|
||||
|
||||
moveResponse.iX = moveData->iX;
|
||||
moveResponse.iY = moveData->iY;
|
||||
moveResponse.iZ = moveData->iZ;
|
||||
moveResponse.iAngle = moveData->iAngle;
|
||||
moveResponse.fVX = moveData->fVX;
|
||||
moveResponse.fVY = moveData->fVY;
|
||||
moveResponse.fVZ = moveData->fVZ;
|
||||
|
||||
moveResponse.iSpeed = moveData->iSpeed;
|
||||
moveResponse.iCliTime = moveData->iCliTime; // maybe don't send this??? seems unneeded...
|
||||
moveResponse.iSvrTime = tm;
|
||||
|
||||
for (CNSocket* otherSock : players[sock].viewable) {
|
||||
sP_FE2CL_PC_MOVE* moveResponse = (sP_FE2CL_PC_MOVE*)xmalloc(sizeof(sP_FE2CL_PC_MOVE));
|
||||
|
||||
moveResponse->iID = players[sock].plr.iID;
|
||||
moveResponse->cKeyValue = moveData->cKeyValue;
|
||||
|
||||
moveResponse->iX = moveData->iX;
|
||||
moveResponse->iY = moveData->iY;
|
||||
moveResponse->iZ = moveData->iZ;
|
||||
moveResponse->iAngle = moveData->iAngle;
|
||||
moveResponse->fVX = moveData->fVX;
|
||||
moveResponse->fVY = moveData->fVY;
|
||||
moveResponse->fVZ = moveData->fVZ;
|
||||
|
||||
moveResponse->iSpeed = moveData->iSpeed;
|
||||
moveResponse->iCliTime = moveData->iCliTime; // maybe don't send this??? seems unneeded...
|
||||
moveResponse->iSvrTime = tm;
|
||||
|
||||
otherSock->sendPacket(new CNPacketData((void*)moveResponse, P_FE2CL_PC_MOVE, sizeof(sP_FE2CL_PC_MOVE), otherSock->getFEKey()));
|
||||
otherSock->sendPacket((void*)&moveResponse, P_FE2CL_PC_MOVE, sizeof(sP_FE2CL_PC_MOVE));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::stopPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_STOP))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_STOP* stopData = (sP_CL2FE_REQ_PC_STOP*)data->buf;
|
||||
updatePlayerPosition(sock, stopData->iX, stopData->iY, stopData->iZ);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2FE_REQ_PC_STOP:" << std::endl;
|
||||
std::cout << "\tX: " << stopData->iX << std::endl;
|
||||
std::cout << "\tY: " << stopData->iY << std::endl;
|
||||
std::cout << "\tZ: " << stopData->iZ << std::endl;
|
||||
)
|
||||
|
||||
uint64_t tm = getTime();
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_STOP, stopResponse);
|
||||
|
||||
stopResponse.iID = players[sock].plr->iID;
|
||||
|
||||
stopResponse.iX = stopData->iX;
|
||||
stopResponse.iY = stopData->iY;
|
||||
stopResponse.iZ = stopData->iZ;
|
||||
|
||||
stopResponse.iCliTime = stopData->iCliTime; // maybe don't send this??? seems unneeded...
|
||||
stopResponse.iSvrTime = tm;
|
||||
|
||||
for (CNSocket* otherSock : players[sock].viewable) {
|
||||
sP_FE2CL_PC_STOP* stopResponse = (sP_FE2CL_PC_STOP*)xmalloc(sizeof(sP_FE2CL_PC_STOP));
|
||||
|
||||
stopResponse->iID = players[sock].plr.iID;
|
||||
|
||||
stopResponse->iX = stopData->iX;
|
||||
stopResponse->iY = stopData->iY;
|
||||
stopResponse->iZ = stopData->iZ;
|
||||
|
||||
stopResponse->iCliTime = stopData->iCliTime; // maybe don't send this??? seems unneeded...
|
||||
stopResponse->iSvrTime = tm;
|
||||
|
||||
otherSock->sendPacket(new CNPacketData((void*)stopResponse, P_FE2CL_PC_STOP, sizeof(sP_FE2CL_PC_STOP), otherSock->getFEKey()));
|
||||
otherSock->sendPacket((void*)&stopResponse, P_FE2CL_PC_STOP, sizeof(sP_FE2CL_PC_STOP));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::jumpPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_JUMP))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_JUMP* jumpData = (sP_CL2FE_REQ_PC_JUMP*)data->buf;
|
||||
updatePlayerPosition(sock, jumpData->iX, jumpData->iY, jumpData->iZ);
|
||||
|
||||
uint64_t tm = getTime();
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_JUMP, jumpResponse);
|
||||
|
||||
jumpResponse.iID = players[sock].plr->iID;
|
||||
jumpResponse.cKeyValue = jumpData->cKeyValue;
|
||||
|
||||
jumpResponse.iX = jumpData->iX;
|
||||
jumpResponse.iY = jumpData->iY;
|
||||
jumpResponse.iZ = jumpData->iZ;
|
||||
jumpResponse.iAngle = jumpData->iAngle;
|
||||
jumpResponse.iVX = jumpData->iVX;
|
||||
jumpResponse.iVY = jumpData->iVY;
|
||||
jumpResponse.iVZ = jumpData->iVZ;
|
||||
|
||||
jumpResponse.iSpeed = jumpData->iSpeed;
|
||||
jumpResponse.iCliTime = jumpData->iCliTime; // maybe don't send this??? seems unneeded...
|
||||
jumpResponse.iSvrTime = tm;
|
||||
|
||||
for (CNSocket* otherSock : players[sock].viewable) {
|
||||
sP_FE2CL_PC_JUMP* jumpResponse = (sP_FE2CL_PC_JUMP*)xmalloc(sizeof(sP_FE2CL_PC_JUMP));
|
||||
otherSock->sendPacket((void*)&jumpResponse, P_FE2CL_PC_JUMP, sizeof(sP_FE2CL_PC_JUMP));
|
||||
}
|
||||
}
|
||||
|
||||
jumpResponse->iID = players[sock].plr.iID;
|
||||
jumpResponse->cKeyValue = jumpData->cKeyValue;
|
||||
void PlayerManager::jumppadPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_JUMPPAD))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
jumpResponse->iX = jumpData->iX;
|
||||
jumpResponse->iY = jumpData->iY;
|
||||
jumpResponse->iZ = jumpData->iZ;
|
||||
jumpResponse->iAngle = jumpData->iAngle;
|
||||
jumpResponse->iVX = jumpData->iVX;
|
||||
jumpResponse->iVY = jumpData->iVY;
|
||||
jumpResponse->iVZ = jumpData->iVZ;
|
||||
|
||||
jumpResponse->iSpeed = jumpData->iSpeed;
|
||||
jumpResponse->iCliTime = jumpData->iCliTime; // maybe don't send this??? seems unneeded...
|
||||
jumpResponse->iSvrTime = tm;
|
||||
sP_CL2FE_REQ_PC_JUMPPAD* jumppadData = (sP_CL2FE_REQ_PC_JUMPPAD*)data->buf;
|
||||
updatePlayerPosition(sock, jumppadData->iX, jumppadData->iY, jumppadData->iZ);
|
||||
|
||||
otherSock->sendPacket(new CNPacketData((void*)jumpResponse, P_FE2CL_PC_JUMP, sizeof(sP_FE2CL_PC_JUMP), otherSock->getFEKey()));
|
||||
uint64_t tm = getTime();
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_JUMPPAD, jumppadResponse);
|
||||
|
||||
jumppadResponse.iPC_ID = players[sock].plr->iID;
|
||||
jumppadResponse.cKeyValue = jumppadData->cKeyValue;
|
||||
|
||||
jumppadResponse.iX = jumppadData->iX;
|
||||
jumppadResponse.iY = jumppadData->iY;
|
||||
jumppadResponse.iZ = jumppadData->iZ;
|
||||
jumppadResponse.iVX = jumppadData->iVX;
|
||||
jumppadResponse.iVY = jumppadData->iVY;
|
||||
jumppadResponse.iVZ = jumppadData->iVZ;
|
||||
|
||||
jumppadResponse.iCliTime = jumppadData->iCliTime;
|
||||
jumppadResponse.iSvrTime = tm;
|
||||
|
||||
for (CNSocket* otherSock : players[sock].viewable) {
|
||||
otherSock->sendPacket((void*)&jumppadResponse, P_FE2CL_PC_JUMPPAD, sizeof(sP_FE2CL_PC_JUMPPAD));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::launchPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_LAUNCHER))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_LAUNCHER* launchData = (sP_CL2FE_REQ_PC_LAUNCHER*)data->buf;
|
||||
updatePlayerPosition(sock, launchData->iX, launchData->iY, launchData->iZ);
|
||||
|
||||
uint64_t tm = getTime();
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_LAUNCHER, launchResponse);
|
||||
|
||||
launchResponse.iPC_ID = players[sock].plr->iID;
|
||||
|
||||
launchResponse.iX = launchData->iX;
|
||||
launchResponse.iY = launchData->iY;
|
||||
launchResponse.iZ = launchData->iZ;
|
||||
launchResponse.iVX = launchData->iVX;
|
||||
launchResponse.iVY = launchData->iVY;
|
||||
launchResponse.iVZ = launchData->iVZ;
|
||||
launchResponse.iSpeed = launchData->iSpeed;
|
||||
launchResponse.iAngle = launchData->iAngle;
|
||||
|
||||
launchResponse.iCliTime = launchData->iCliTime;
|
||||
launchResponse.iSvrTime = tm;
|
||||
|
||||
for (CNSocket* otherSock : players[sock].viewable) {
|
||||
otherSock->sendPacket((void*)&launchResponse, P_FE2CL_PC_LAUNCHER, sizeof(sP_FE2CL_PC_LAUNCHER));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::ziplinePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_ZIPLINE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_ZIPLINE* ziplineData = (sP_CL2FE_REQ_PC_ZIPLINE*)data->buf;
|
||||
updatePlayerPosition(sock, ziplineData->iX, ziplineData->iY, ziplineData->iZ);
|
||||
|
||||
uint64_t tm = getTime();
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_ZIPLINE, ziplineResponse);
|
||||
|
||||
ziplineResponse.iPC_ID = players[sock].plr->iID;
|
||||
ziplineResponse.iCliTime = ziplineData->iCliTime;
|
||||
ziplineResponse.iSvrTime = tm;
|
||||
ziplineResponse.iX = ziplineData->iX;
|
||||
ziplineResponse.iY = ziplineData->iY;
|
||||
ziplineResponse.iZ = ziplineData->iZ;
|
||||
ziplineResponse.fVX = ziplineData->fVX;
|
||||
ziplineResponse.fVY = ziplineData->fVY;
|
||||
ziplineResponse.fVZ = ziplineData->fVZ;
|
||||
ziplineResponse.fMovDistance = ziplineData->fMovDistance;
|
||||
ziplineResponse.fMaxDistance = ziplineData->fMaxDistance;
|
||||
ziplineResponse.fDummy = ziplineData->fDummy; //wtf is this for?
|
||||
ziplineResponse.iStX = ziplineData->iStX;
|
||||
ziplineResponse.iStY = ziplineData->iStY;
|
||||
ziplineResponse.iStZ = ziplineData->iStZ;
|
||||
ziplineResponse.bDown = ziplineData->bDown;
|
||||
ziplineResponse.iSpeed = ziplineData->iSpeed;
|
||||
ziplineResponse.iAngle = ziplineData->iAngle;
|
||||
ziplineResponse.iRollMax = ziplineData->iRollMax;
|
||||
ziplineResponse.iRoll = ziplineData->iRoll;
|
||||
|
||||
for (CNSocket* otherSock : players[sock].viewable) {
|
||||
otherSock->sendPacket((void*)&ziplineResponse, P_FE2CL_PC_ZIPLINE, sizeof(sP_FE2CL_PC_ZIPLINE));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::movePlatformPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_MOVEPLATFORM))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_MOVEPLATFORM* platformData = (sP_CL2FE_REQ_PC_MOVEPLATFORM*)data->buf;
|
||||
updatePlayerPosition(sock, platformData->iX, platformData->iY, platformData->iZ);
|
||||
|
||||
uint64_t tm = getTime();
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_MOVEPLATFORM, platResponse);
|
||||
|
||||
platResponse.iPC_ID = players[sock].plr->iID;
|
||||
platResponse.iCliTime = platformData->iCliTime;
|
||||
platResponse.iSvrTime = tm;
|
||||
platResponse.iX = platformData->iX;
|
||||
platResponse.iY = platformData->iY;
|
||||
platResponse.iZ = platformData->iZ;
|
||||
platResponse.iAngle = platformData->iAngle;
|
||||
platResponse.fVX = platformData->fVX;
|
||||
platResponse.fVY = platformData->fVY;
|
||||
platResponse.fVZ = platformData->fVZ;
|
||||
platResponse.iLcX = platformData->iLcX;
|
||||
platResponse.iLcY = platformData->iLcY;
|
||||
platResponse.iLcZ = platformData->iLcZ;
|
||||
platResponse.iSpeed = platformData->iSpeed;
|
||||
platResponse.bDown = platformData->bDown;
|
||||
platResponse.cKeyValue = platformData->cKeyValue;
|
||||
platResponse.iPlatformID = platformData->iPlatformID;
|
||||
|
||||
for (CNSocket* otherSock : players[sock].viewable) {
|
||||
otherSock->sendPacket((void*)&platResponse, P_FE2CL_PC_MOVEPLATFORM, sizeof(sP_FE2CL_PC_MOVEPLATFORM));
|
||||
}
|
||||
}
|
||||
|
||||
sP_FE2CL_PC_MOVEPLATFORM* platResponse = (sP_FE2CL_PC_MOVEPLATFORM*)xmalloc(sizeof(sP_FE2CL_PC_MOVEPLATFORM));
|
||||
void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_SLOPE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
platResponse->iPC_ID = players[sock].plr.iID;
|
||||
platResponse->iCliTime = platformData->iCliTime;
|
||||
platResponse->iSvrTime = tm;
|
||||
platResponse->iX = platformData->iX;
|
||||
platResponse->iY = platformData->iY;
|
||||
platResponse->iZ = platformData->iZ;
|
||||
platResponse->iAngle = platformData->iAngle;
|
||||
platResponse->fVX = platformData->fVX;
|
||||
platResponse->fVY = platformData->fVY;
|
||||
platResponse->fVZ = platformData->fVZ;
|
||||
platResponse->iLcX = platformData->iLcX;
|
||||
platResponse->iLcY = platformData->iLcY;
|
||||
platResponse->iLcZ = platformData->iLcZ;
|
||||
platResponse->iSpeed = platformData->iSpeed;
|
||||
platResponse->bDown = platformData->bDown;
|
||||
platResponse->cKeyValue = platformData->cKeyValue;
|
||||
platResponse->iPlatformID = platformData->iPlatformID;
|
||||
sP_CL2FE_REQ_PC_SLOPE* slopeData = (sP_CL2FE_REQ_PC_SLOPE*)data->buf;
|
||||
updatePlayerPosition(sock, slopeData->iX, slopeData->iY, slopeData->iZ);
|
||||
|
||||
otherSock->sendPacket(new CNPacketData((void*)platResponse, P_FE2CL_PC_MOVEPLATFORM, sizeof(sP_FE2CL_PC_MOVEPLATFORM), otherSock->getFEKey()));
|
||||
uint64_t tm = getTime();
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_SLOPE, slopeResponse);
|
||||
|
||||
slopeResponse.iPC_ID = players[sock].plr->iID;
|
||||
slopeResponse.iCliTime = slopeData->iCliTime;
|
||||
slopeResponse.iSvrTime = tm;
|
||||
slopeResponse.iX = slopeData->iX;
|
||||
slopeResponse.iY = slopeData->iY;
|
||||
slopeResponse.iZ = slopeData->iZ;
|
||||
slopeResponse.iAngle = slopeData->iAngle;
|
||||
slopeResponse.fVX = slopeData->fVX;
|
||||
slopeResponse.fVY = slopeData->fVY;
|
||||
slopeResponse.fVZ = slopeData->fVZ;
|
||||
slopeResponse.iSpeed = slopeData->iSpeed;
|
||||
slopeResponse.cKeyValue = slopeData->cKeyValue;
|
||||
slopeResponse.iSlopeID = slopeData->iSlopeID;
|
||||
|
||||
for (CNSocket* otherSock : players[sock].viewable) {
|
||||
otherSock->sendPacket((void*)&slopeResponse, P_FE2CL_PC_SLOPE, sizeof(sP_FE2CL_PC_SLOPE));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GOTO))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_GOTO* gotoData = (sP_CL2FE_REQ_PC_GOTO*)data->buf;
|
||||
sP_FE2CL_REP_PC_GOTO_SUCC* response = (sP_FE2CL_REP_PC_GOTO_SUCC*)xmalloc(sizeof(sP_FE2CL_REP_PC_GOTO_SUCC));
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_GOTO_SUCC, response);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2FE_REQ_PC_GOTO:" << std::endl;
|
||||
@@ -338,16 +536,19 @@ void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
std::cout << "\tZ: " << gotoData->iToZ << std::endl;
|
||||
)
|
||||
|
||||
response->iX = gotoData->iToX;
|
||||
response->iY = gotoData->iToY;
|
||||
response->iZ = gotoData->iToZ;
|
||||
response.iX = gotoData->iToX;
|
||||
response.iY = gotoData->iToY;
|
||||
response.iZ = gotoData->iToZ;
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC), sock->getFEKey()));
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC));
|
||||
}
|
||||
|
||||
void PlayerManager::setSpecialPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_SET_VALUE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
sP_CL2FE_GM_REQ_PC_SET_VALUE* setData = (sP_CL2FE_GM_REQ_PC_SET_VALUE*)data->buf;
|
||||
sP_FE2CL_GM_REP_PC_SET_VALUE* response = (sP_FE2CL_GM_REP_PC_SET_VALUE*)xmalloc(sizeof(sP_FE2CL_GM_REP_PC_SET_VALUE));
|
||||
INITSTRUCT(sP_FE2CL_GM_REP_PC_SET_VALUE, response);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << "P_CL2FE_GM_REQ_PC_SET_VALUE:" << std::endl;
|
||||
@@ -356,9 +557,157 @@ void PlayerManager::setSpecialPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
std::cout << "\tSetValue: " << setData->iSetValue << std::endl;
|
||||
)
|
||||
|
||||
response->iPC_ID = setData->iPC_ID;
|
||||
response->iSetValue = setData->iSetValue;
|
||||
response->iSetValueType = setData->iSetValueType;
|
||||
response.iPC_ID = setData->iPC_ID;
|
||||
response.iSetValue = setData->iSetValue;
|
||||
response.iSetValueType = setData->iSetValueType;
|
||||
|
||||
sock->sendPacket(new CNPacketData((void*)response, P_FE2CL_GM_REP_PC_SET_VALUE, sizeof(sP_FE2CL_GM_REP_PC_SET_VALUE), sock->getFEKey()));
|
||||
}
|
||||
sock->sendPacket((void*)&response, P_FE2CL_GM_REP_PC_SET_VALUE, sizeof(sP_FE2CL_GM_REP_PC_SET_VALUE));
|
||||
}
|
||||
|
||||
void PlayerManager::heartbeatPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
players[sock].lastHeartbeat = getTime();
|
||||
}
|
||||
|
||||
void PlayerManager::exitGame(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_EXIT))
|
||||
return;
|
||||
|
||||
sP_CL2FE_REQ_PC_EXIT* exitData = (sP_CL2FE_REQ_PC_EXIT*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_EXIT_SUCC, response);
|
||||
|
||||
response.iID = exitData->iID;
|
||||
response.iExitCode = 1;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC));
|
||||
}
|
||||
|
||||
void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_REGEN))
|
||||
return;
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
WarpLocation target = PlayerManager::getRespawnPoint(plr);
|
||||
|
||||
// players respawn at same spot they died at for now...
|
||||
sP_CL2FE_REQ_PC_REGEN* reviveData = (sP_CL2FE_REQ_PC_REGEN*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_REGEN_SUCC, response);
|
||||
response.bMoveLocation = reviveData->eIL;
|
||||
response.PCRegenData.iMapNum = reviveData->iIndex;
|
||||
response.PCRegenData.iHP = 1000 * plr->level;
|
||||
response.PCRegenData.iX = target.x;
|
||||
response.PCRegenData.iY = target.y;
|
||||
response.PCRegenData.iZ = target.z;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_REGEN_SUCC, sizeof(sP_FE2CL_REP_PC_REGEN_SUCC));
|
||||
}
|
||||
|
||||
void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
PlayerView& plr = PlayerManager::players[sock];
|
||||
|
||||
if (plr.plr->Equip[8].iID > 0) {
|
||||
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_SUCC, response);
|
||||
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC));
|
||||
|
||||
//send to other players
|
||||
plr.plr->iPCState = 8;
|
||||
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
|
||||
response2.iPC_ID = plr.plr->iID;
|
||||
response2.iState = 8;
|
||||
|
||||
for (CNSocket* otherSock : plr.viewable) {
|
||||
otherSock->sendPacket((void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
|
||||
}
|
||||
|
||||
} else {
|
||||
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_FAIL, response);
|
||||
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_FAIL, sizeof(sP_FE2CL_PC_VEHICLE_ON_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_VEHICLE_OFF_SUCC, response);
|
||||
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_OFF_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_OFF_SUCC));
|
||||
|
||||
PlayerView plr = PlayerManager::players[sock];
|
||||
|
||||
//send to other players
|
||||
plr.plr->iPCState = 0;
|
||||
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
|
||||
response2.iPC_ID = plr.plr->iID;
|
||||
response2.iState = 0;
|
||||
|
||||
for (CNSocket* otherSock : plr.viewable) {
|
||||
otherSock->sendPacket((void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH* specialData = (sP_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, response);
|
||||
|
||||
response.iPC_ID = specialData->iPC_ID;
|
||||
response.iReqSpecialStateFlag = specialData->iSpecialStateFlag;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC));
|
||||
}
|
||||
|
||||
void PlayerManager::changePlayerGuide(CNSocket *sock, CNPacketData *data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_CHANGE_MENTOR))
|
||||
return;
|
||||
|
||||
sP_CL2FE_REQ_PC_CHANGE_MENTOR *pkt = (sP_CL2FE_REQ_PC_CHANGE_MENTOR*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_CHANGE_MENTOR_SUCC, resp);
|
||||
Player *plr = getPlayer(sock);
|
||||
|
||||
resp.iMentor = pkt->iMentor;
|
||||
resp.iMentorCnt = 1;
|
||||
resp.iFusionMatter = plr->fusionmatter; // no cost
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_CHANGE_MENTOR_SUCC, sizeof(sP_FE2CL_REP_PC_CHANGE_MENTOR_SUCC));
|
||||
}
|
||||
|
||||
#pragma region Helper methods
|
||||
Player *PlayerManager::getPlayer(CNSocket* key) {
|
||||
return players[key].plr;
|
||||
}
|
||||
|
||||
WarpLocation PlayerManager::getRespawnPoint(Player *plr) {
|
||||
WarpLocation best;
|
||||
uint32_t curDist, bestDist = UINT32_MAX;
|
||||
|
||||
for (auto targ : NPCManager::RespawnPoints) {
|
||||
curDist = sqrt(pow(plr->x - targ.x, 2) + pow(plr->y - targ.y, 2));
|
||||
if (curDist < bestDist) {
|
||||
best = targ;
|
||||
bestDist = curDist;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
bool PlayerManager::isAccountInUse(int accountId) {
|
||||
std::map<CNSocket*, PlayerView>::iterator it;
|
||||
for (it = PlayerManager::players.begin(); it != PlayerManager::players.end(); it++)
|
||||
{
|
||||
if (it->second.plr->accountId == accountId)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PlayerManager::exitDuplicate(int accountId) {
|
||||
std::map<CNSocket*, PlayerView>::iterator it;
|
||||
for (it = PlayerManager::players.begin(); it != PlayerManager::players.end(); it++)
|
||||
{
|
||||
if (it->second.plr->accountId == accountId)
|
||||
{
|
||||
CNSocket* sock = it->first;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_EXIT_DUPLICATE, resp);
|
||||
resp.iErrorCode = 0;
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_EXIT_DUPLICATE, sizeof(sP_FE2CL_REP_PC_EXIT_DUPLICATE));
|
||||
sock->kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#ifndef _PM_HPP
|
||||
#define _PM_HPP
|
||||
#pragma once
|
||||
|
||||
#include "Player.hpp"
|
||||
#include "CNProtocol.hpp"
|
||||
@@ -9,9 +8,13 @@
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
struct WarpLocation;
|
||||
|
||||
struct PlayerView {
|
||||
std::list<CNSocket*> viewable;
|
||||
Player plr;
|
||||
std::list<int32_t> viewableNPCs;
|
||||
Player *plr;
|
||||
uint64_t lastHeartbeat;
|
||||
};
|
||||
|
||||
|
||||
@@ -21,19 +24,35 @@ namespace PlayerManager {
|
||||
|
||||
void addPlayer(CNSocket* key, Player plr);
|
||||
void removePlayer(CNSocket* key);
|
||||
Player getPlayer(CNSocket* key);
|
||||
|
||||
void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z);
|
||||
std::list<CNSocket*> getNearbyPlayers(int X, int Y, int dist);
|
||||
|
||||
void enterPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void loadPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void movePlayer(CNSocket* sock, CNPacketData* data);
|
||||
void stopPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void jumpPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void jumppadPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void launchPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void ziplinePlayer(CNSocket* sock, CNPacketData* data);
|
||||
void movePlatformPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void moveSlopePlayer(CNSocket* sock, CNPacketData* data);
|
||||
void gotoPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void setSpecialPlayer(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
}
|
||||
void heartbeatPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void revivePlayer(CNSocket* sock, CNPacketData* data);
|
||||
void exitGame(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
#endif
|
||||
void setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void changePlayerGuide(CNSocket *sock, CNPacketData *data);
|
||||
|
||||
void enterPlayerVehicle(CNSocket* sock, CNPacketData* data);
|
||||
void exitPlayerVehicle(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
Player *getPlayer(CNSocket* key);
|
||||
WarpLocation getRespawnPoint(Player *plr);
|
||||
|
||||
bool isAccountInUse(int accountId);
|
||||
void exitDuplicate(int accountId);
|
||||
}
|
||||
|
18
src/TransportManager.cpp
Normal file
18
src/TransportManager.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "CNShardServer.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "TransportManager.hpp"
|
||||
|
||||
void TransportManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler);
|
||||
}
|
||||
|
||||
void TransportManager::transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION* transport = (sP_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION*)data->buf;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, resp);
|
||||
resp.eTT = transport->eTT;
|
||||
resp.iLocationID = transport->iLocationID;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, sizeof(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC));
|
||||
}
|
9
src/TransportManager.hpp
Normal file
9
src/TransportManager.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CNShardServer.hpp"
|
||||
|
||||
namespace TransportManager {
|
||||
void init();
|
||||
|
||||
void transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data);
|
||||
}
|
25447
src/contrib/JSON.hpp
Normal file
25447
src/contrib/JSON.hpp
Normal file
File diff suppressed because it is too large
Load Diff
31
src/contrib/bcrypt/BCrypt.hpp
Normal file
31
src/contrib/bcrypt/BCrypt.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __BCRYPT__
|
||||
#define __BCRYPT__
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winbcrypt.h"
|
||||
#else
|
||||
|
||||
#include "bcrypt.h"
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
class BCrypt {
|
||||
public:
|
||||
static std::string generateHash(const std::string & password, int workload = 12){
|
||||
char salt[BCRYPT_HASHSIZE];
|
||||
char hash[BCRYPT_HASHSIZE];
|
||||
int ret;
|
||||
ret = bcrypt_gensalt(workload, salt);
|
||||
if(ret != 0)throw std::runtime_error{"bcrypt: can not generate salt"};
|
||||
ret = bcrypt_hashpw(password.c_str(), salt, hash);
|
||||
if(ret != 0)throw std::runtime_error{"bcrypt: can not generate hash"};
|
||||
return std::string{hash};
|
||||
}
|
||||
|
||||
static bool validatePassword(const std::string & password, const std::string & hash){
|
||||
return (bcrypt_checkpw(password.c_str(), hash.c_str()) == 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __BCRYPT__
|
230
src/contrib/bcrypt/bcrypt.c
Normal file
230
src/contrib/bcrypt/bcrypt.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* bcrypt wrapper library
|
||||
*
|
||||
* Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all copyright
|
||||
* and related and neighboring rights to this software to the public domain
|
||||
* worldwide. This software is distributed without any warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef _WIN32
|
||||
#elif _WIN64
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32 || _WIN64
|
||||
// On windows we need to generate random bytes differently.
|
||||
typedef __int64 ssize_t;
|
||||
#define BCRYPT_HASHSIZE 60
|
||||
|
||||
#include "bcrypt.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h> /* CryptAcquireContext, CryptGenRandom */
|
||||
#else
|
||||
#include "bcrypt.h"
|
||||
#include "ow-crypt.h"
|
||||
#endif
|
||||
|
||||
#define RANDBYTES (16)
|
||||
|
||||
static int try_close(int fd)
|
||||
{
|
||||
int ret;
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
ret = close(fd);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int try_read(int fd, char *out, size_t count)
|
||||
{
|
||||
size_t total;
|
||||
ssize_t partial;
|
||||
|
||||
total = 0;
|
||||
while (total < count)
|
||||
{
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
partial = read(fd, out + total, count - total);
|
||||
if (partial == -1 && errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (partial < 1)
|
||||
return -1;
|
||||
|
||||
total += partial;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a best effort implementation. Nothing prevents a compiler from
|
||||
* optimizing this function and making it vulnerable to timing attacks, but
|
||||
* this method is commonly used in crypto libraries like NaCl.
|
||||
*
|
||||
* Return value is zero if both strings are equal and nonzero otherwise.
|
||||
*/
|
||||
static int timing_safe_strcmp(const char *str1, const char *str2)
|
||||
{
|
||||
const unsigned char *u1;
|
||||
const unsigned char *u2;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
int len1 = strlen(str1);
|
||||
int len2 = strlen(str2);
|
||||
|
||||
/* In our context both strings should always have the same length
|
||||
* because they will be hashed passwords. */
|
||||
if (len1 != len2)
|
||||
return 1;
|
||||
|
||||
/* Force unsigned for bitwise operations. */
|
||||
u1 = (const unsigned char *)str1;
|
||||
u2 = (const unsigned char *)str2;
|
||||
|
||||
ret = 0;
|
||||
for (i = 0; i < len1; ++i)
|
||||
ret |= (u1[i] ^ u2[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
|
||||
{
|
||||
int fd;
|
||||
char input[RANDBYTES];
|
||||
int workf;
|
||||
char *aux;
|
||||
|
||||
// Note: Windows does not have /dev/urandom sadly.
|
||||
#ifdef _WIN32 || _WIN64
|
||||
HCRYPTPROV p;
|
||||
ULONG i;
|
||||
|
||||
// Acquire a crypt context for generating random bytes.
|
||||
if (CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (CryptGenRandom(p, RANDBYTES, (BYTE*)input) == FALSE) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (CryptReleaseContext(p, 0) == FALSE) {
|
||||
return 3;
|
||||
}
|
||||
#else
|
||||
// Get random bytes on Unix/Linux.
|
||||
fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd == -1)
|
||||
return 1;
|
||||
|
||||
if (try_read(fd, input, RANDBYTES) != 0) {
|
||||
if (try_close(fd) != 0)
|
||||
return 4;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (try_close(fd) != 0)
|
||||
return 3;
|
||||
#endif
|
||||
|
||||
/* Generate salt. */
|
||||
workf = (factor < 4 || factor > 31)?12:factor;
|
||||
aux = crypt_gensalt_rn("$2a$", workf, input, RANDBYTES,
|
||||
salt, BCRYPT_HASHSIZE);
|
||||
return (aux == NULL)?5:0;
|
||||
}
|
||||
|
||||
int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE])
|
||||
{
|
||||
char *aux;
|
||||
aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE);
|
||||
return (aux == NULL)?1:0;
|
||||
}
|
||||
|
||||
int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE])
|
||||
{
|
||||
int ret;
|
||||
char outhash[BCRYPT_HASHSIZE];
|
||||
|
||||
ret = bcrypt_hashpw(passwd, hash, outhash);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
return timing_safe_strcmp(hash, outhash);
|
||||
}
|
||||
|
||||
#ifdef TEST_BCRYPT
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
clock_t before;
|
||||
clock_t after;
|
||||
char salt[BCRYPT_HASHSIZE];
|
||||
char hash[BCRYPT_HASHSIZE];
|
||||
int ret;
|
||||
|
||||
const char pass[] = "hi,mom";
|
||||
const char hash1[] = "$2a$10$VEVmGHy4F4XQMJ3eOZJAUeb.MedU0W10pTPCuf53eHdKJPiSE8sMK";
|
||||
const char hash2[] = "$2a$10$3F0BVk5t8/aoS.3ddaB3l.fxg5qvafQ9NybxcpXLzMeAt.nVWn.NO";
|
||||
|
||||
ret = bcrypt_gensalt(12, salt);
|
||||
assert(ret == 0);
|
||||
printf("Generated salt: %s\n", salt);
|
||||
before = clock();
|
||||
ret = bcrypt_hashpw("testtesttest", salt, hash);
|
||||
assert(ret == 0);
|
||||
after = clock();
|
||||
printf("Hashed password: %s\n", hash);
|
||||
printf("Time taken: %f seconds\n",
|
||||
(double)(after - before) / CLOCKS_PER_SEC);
|
||||
|
||||
ret = bcrypt_hashpw(pass, hash1, hash);
|
||||
assert(ret == 0);
|
||||
printf("First hash check: %s\n", (strcmp(hash1, hash) == 0)?"OK":"FAIL");
|
||||
ret = bcrypt_hashpw(pass, hash2, hash);
|
||||
assert(ret == 0);
|
||||
printf("Second hash check: %s\n", (strcmp(hash2, hash) == 0)?"OK":"FAIL");
|
||||
|
||||
before = clock();
|
||||
ret = (bcrypt_checkpw(pass, hash1) == 0);
|
||||
after = clock();
|
||||
printf("First hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
|
||||
printf("Time taken: %f seconds\n",
|
||||
(double)(after - before) / CLOCKS_PER_SEC);
|
||||
|
||||
before = clock();
|
||||
ret = (bcrypt_checkpw(pass, hash2) == 0);
|
||||
after = clock();
|
||||
printf("Second hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
|
||||
printf("Time taken: %f seconds\n",
|
||||
(double)(after - before) / CLOCKS_PER_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
97
src/contrib/bcrypt/bcrypt.h
Normal file
97
src/contrib/bcrypt/bcrypt.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef BCRYPT_H_
|
||||
#define BCRYPT_H_
|
||||
/*
|
||||
* bcrypt wrapper library
|
||||
*
|
||||
* Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all copyright
|
||||
* and related and neighboring rights to this software to the public domain
|
||||
* worldwide. This software is distributed without any warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#define BCRYPT_HASHSIZE (64)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function expects a work factor between 4 and 31 and a char array to
|
||||
* store the resulting generated salt. The char array should typically have
|
||||
* BCRYPT_HASHSIZE bytes at least. If the provided work factor is not in the
|
||||
* previous range, it will default to 12.
|
||||
*
|
||||
* The return value is zero if the salt could be correctly generated and
|
||||
* nonzero otherwise.
|
||||
*
|
||||
*/
|
||||
int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]);
|
||||
|
||||
/*
|
||||
* This function expects a password to be hashed, a salt to hash the password
|
||||
* with and a char array to leave the result. Both the salt and the hash
|
||||
* parameters should have room for BCRYPT_HASHSIZE characters at least.
|
||||
*
|
||||
* It can also be used to verify a hashed password. In that case, provide the
|
||||
* expected hash in the salt parameter and verify the output hash is the same
|
||||
* as the input hash. However, to avoid timing attacks, it's better to use
|
||||
* bcrypt_checkpw when verifying a password.
|
||||
*
|
||||
* The return value is zero if the password could be hashed and nonzero
|
||||
* otherwise.
|
||||
*/
|
||||
int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE],
|
||||
char hash[BCRYPT_HASHSIZE]);
|
||||
|
||||
/*
|
||||
* This function expects a password and a hash to verify the password against.
|
||||
* The internal implementation is tuned to avoid timing attacks.
|
||||
*
|
||||
* The return value will be -1 in case of errors, zero if the provided password
|
||||
* matches the given hash and greater than zero if no errors are found and the
|
||||
* passwords don't match.
|
||||
*
|
||||
*/
|
||||
int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]);
|
||||
|
||||
/*
|
||||
* Brief Example
|
||||
* -------------
|
||||
*
|
||||
* Hashing a password:
|
||||
*
|
||||
* char salt[BCRYPT_HASHSIZE];
|
||||
* char hash[BCRYPT_HASHSIZE];
|
||||
* int ret;
|
||||
*
|
||||
* ret = bcrypt_gensalt(12, salt);
|
||||
* assert(ret == 0);
|
||||
* ret = bcrypt_hashpw("thepassword", salt, hash);
|
||||
* assert(ret == 0);
|
||||
*
|
||||
*
|
||||
* Verifying a password:
|
||||
*
|
||||
* int ret;
|
||||
*
|
||||
* ret = bcrypt_checkpw("thepassword", "expectedhash");
|
||||
* assert(ret != -1);
|
||||
*
|
||||
* if (ret == 0) {
|
||||
* printf("The password matches\n");
|
||||
* } else {
|
||||
* printf("The password does NOT match\n");
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
24
src/contrib/bcrypt/crypt.h
Normal file
24
src/contrib/bcrypt/crypt.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Written by Solar Designer <solar at openwall.com> in 2000-2002.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2000-2002 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See crypt_blowfish.c for more information.
|
||||
*/
|
||||
|
||||
//#include <gnu-crypt.h>
|
||||
|
||||
#if defined(_OW_SOURCE) || defined(__USE_OW)
|
||||
#define __SKIP_GNU
|
||||
#undef __SKIP_OW
|
||||
#include <ow-crypt.h>
|
||||
#undef __SKIP_GNU
|
||||
#endif
|
911
src/contrib/bcrypt/crypt_blowfish.c
Normal file
911
src/contrib/bcrypt/crypt_blowfish.c
Normal file
@@ -0,0 +1,911 @@
|
||||
/*
|
||||
* The crypt_blowfish homepage is:
|
||||
*
|
||||
* http://www.openwall.com/crypt/
|
||||
*
|
||||
* This code comes from John the Ripper password cracker, with reentrant
|
||||
* and crypt(3) interfaces added, but optimizations specific to password
|
||||
* cracking removed.
|
||||
*
|
||||
* Written by Solar Designer <solar at openwall.com> in 1998-2014.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 1998-2014 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* It is my intent that you should be able to use this on your system,
|
||||
* as part of a software package, or anywhere else to improve security,
|
||||
* ensure compatibility, or for any other purpose. I would appreciate
|
||||
* it if you give credit where it is due and keep your modifications in
|
||||
* the public domain as well, but I don't require that in order to let
|
||||
* you place this code and any modifications you make under a license
|
||||
* of your choice.
|
||||
*
|
||||
* This implementation is fully compatible with OpenBSD's bcrypt.c for prefix
|
||||
* "$2b$", originally by Niels Provos <provos at citi.umich.edu>, and it uses
|
||||
* some of his ideas. The password hashing algorithm was designed by David
|
||||
* Mazieres <dm at lcs.mit.edu>. For information on the level of
|
||||
* compatibility for bcrypt hash prefixes other than "$2b$", please refer to
|
||||
* the comments in BF_set_key() below and to the included crypt(3) man page.
|
||||
*
|
||||
* There's a paper on the algorithm that explains its design decisions:
|
||||
*
|
||||
* http://www.usenix.org/events/usenix99/provos.html
|
||||
*
|
||||
* Some of the tricks in BF_ROUND might be inspired by Eric Young's
|
||||
* Blowfish library (I can't be sure if I would think of something if I
|
||||
* hadn't seen his code).
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef __set_errno
|
||||
#define __set_errno(val) errno = (val)
|
||||
#endif
|
||||
|
||||
/* Just to make sure the prototypes match the actual definitions */
|
||||
#ifdef _WIN32 || _WIN64
|
||||
#include "crypt_blowfish.h"
|
||||
#else
|
||||
#include "crypt_blowfish.h"
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
#define BF_ASM 1
|
||||
#define BF_SCALE 1
|
||||
#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__)
|
||||
#define BF_ASM 0
|
||||
#define BF_SCALE 1
|
||||
#else
|
||||
#define BF_ASM 0
|
||||
#define BF_SCALE 0
|
||||
#endif
|
||||
|
||||
typedef unsigned int BF_word;
|
||||
typedef signed int BF_word_signed;
|
||||
|
||||
/* Number of Blowfish rounds, this is also hardcoded into a few places */
|
||||
#define BF_N 16
|
||||
|
||||
typedef BF_word BF_key[BF_N + 2];
|
||||
|
||||
typedef struct {
|
||||
BF_word S[4][0x100];
|
||||
BF_key P;
|
||||
} BF_ctx;
|
||||
|
||||
/*
|
||||
* Magic IV for 64 Blowfish encryptions that we do at the end.
|
||||
* The string is "OrpheanBeholderScryDoubt" on big-endian.
|
||||
*/
|
||||
static BF_word BF_magic_w[6] = {
|
||||
0x4F727068, 0x65616E42, 0x65686F6C,
|
||||
0x64657253, 0x63727944, 0x6F756274
|
||||
};
|
||||
|
||||
/*
|
||||
* P-box and S-box tables initialized with digits of Pi.
|
||||
*/
|
||||
static BF_ctx BF_init_state = {
|
||||
{
|
||||
{
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
|
||||
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
|
||||
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
|
||||
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
|
||||
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
|
||||
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
|
||||
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
|
||||
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
|
||||
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
|
||||
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
|
||||
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
|
||||
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
|
||||
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
|
||||
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
|
||||
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
|
||||
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
|
||||
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
|
||||
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
|
||||
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
|
||||
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
|
||||
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
|
||||
}, {
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
|
||||
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
|
||||
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
|
||||
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
|
||||
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
|
||||
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
|
||||
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
|
||||
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
|
||||
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
|
||||
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
|
||||
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
|
||||
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
|
||||
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
|
||||
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
|
||||
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
|
||||
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
|
||||
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
|
||||
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
|
||||
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
|
||||
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
|
||||
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
|
||||
}, {
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
|
||||
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
|
||||
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
|
||||
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
|
||||
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
|
||||
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
|
||||
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
|
||||
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
|
||||
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
|
||||
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
|
||||
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
|
||||
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
|
||||
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
|
||||
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
|
||||
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
|
||||
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
|
||||
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
|
||||
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
|
||||
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
|
||||
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
|
||||
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
|
||||
}, {
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
|
||||
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
|
||||
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
|
||||
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
|
||||
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
|
||||
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
|
||||
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
|
||||
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
|
||||
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
|
||||
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
|
||||
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
|
||||
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
|
||||
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
|
||||
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
|
||||
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
|
||||
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
|
||||
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
|
||||
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
|
||||
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
|
||||
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
|
||||
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||||
}
|
||||
}, {
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
0x9216d5d9, 0x8979fb1b
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned char BF_itoa64[64 + 1] =
|
||||
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
static unsigned char BF_atoi64[0x60] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64,
|
||||
64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64,
|
||||
64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
|
||||
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
|
||||
};
|
||||
|
||||
#define BF_safe_atoi64(dst, src) \
|
||||
{ \
|
||||
tmp = (unsigned char)(src); \
|
||||
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
|
||||
tmp = BF_atoi64[tmp]; \
|
||||
if (tmp > 63) return -1; \
|
||||
(dst) = tmp; \
|
||||
}
|
||||
|
||||
static int BF_decode(BF_word *dst, const char *src, int size)
|
||||
{
|
||||
unsigned char *dptr = (unsigned char *)dst;
|
||||
unsigned char *end = dptr + size;
|
||||
const unsigned char *sptr = (const unsigned char *)src;
|
||||
unsigned int tmp, c1, c2, c3, c4;
|
||||
|
||||
do {
|
||||
BF_safe_atoi64(c1, *sptr++);
|
||||
BF_safe_atoi64(c2, *sptr++);
|
||||
*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
|
||||
if (dptr >= end) break;
|
||||
|
||||
BF_safe_atoi64(c3, *sptr++);
|
||||
*dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
|
||||
if (dptr >= end) break;
|
||||
|
||||
BF_safe_atoi64(c4, *sptr++);
|
||||
*dptr++ = ((c3 & 0x03) << 6) | c4;
|
||||
} while (dptr < end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void BF_encode(char *dst, const BF_word *src, int size)
|
||||
{
|
||||
const unsigned char *sptr = (const unsigned char *)src;
|
||||
const unsigned char *end = sptr + size;
|
||||
unsigned char *dptr = (unsigned char *)dst;
|
||||
unsigned int c1, c2;
|
||||
|
||||
do {
|
||||
c1 = *sptr++;
|
||||
*dptr++ = BF_itoa64[c1 >> 2];
|
||||
c1 = (c1 & 0x03) << 4;
|
||||
if (sptr >= end) {
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
break;
|
||||
}
|
||||
|
||||
c2 = *sptr++;
|
||||
c1 |= c2 >> 4;
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
c1 = (c2 & 0x0f) << 2;
|
||||
if (sptr >= end) {
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
break;
|
||||
}
|
||||
|
||||
c2 = *sptr++;
|
||||
c1 |= c2 >> 6;
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
*dptr++ = BF_itoa64[c2 & 0x3f];
|
||||
} while (sptr < end);
|
||||
}
|
||||
|
||||
static void BF_swap(BF_word *x, int count)
|
||||
{
|
||||
static int endianness_check = 1;
|
||||
char *is_little_endian = (char *)&endianness_check;
|
||||
BF_word tmp;
|
||||
|
||||
if (*is_little_endian)
|
||||
do {
|
||||
tmp = *x;
|
||||
tmp = (tmp << 16) | (tmp >> 16);
|
||||
*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
|
||||
} while (--count);
|
||||
}
|
||||
|
||||
#if BF_SCALE
|
||||
/* Architectures which can shift addresses left by 2 bits with no extra cost */
|
||||
#define BF_ROUND(L, R, N) \
|
||||
tmp1 = L & 0xFF; \
|
||||
tmp2 = L >> 8; \
|
||||
tmp2 &= 0xFF; \
|
||||
tmp3 = L >> 16; \
|
||||
tmp3 &= 0xFF; \
|
||||
tmp4 = L >> 24; \
|
||||
tmp1 = data.ctx.S[3][tmp1]; \
|
||||
tmp2 = data.ctx.S[2][tmp2]; \
|
||||
tmp3 = data.ctx.S[1][tmp3]; \
|
||||
tmp3 += data.ctx.S[0][tmp4]; \
|
||||
tmp3 ^= tmp2; \
|
||||
R ^= data.ctx.P[N + 1]; \
|
||||
tmp3 += tmp1; \
|
||||
R ^= tmp3;
|
||||
#else
|
||||
/* Architectures with no complicated addressing modes supported */
|
||||
#define BF_INDEX(S, i) \
|
||||
(*((BF_word *)(((unsigned char *)S) + (i))))
|
||||
#define BF_ROUND(L, R, N) \
|
||||
tmp1 = L & 0xFF; \
|
||||
tmp1 <<= 2; \
|
||||
tmp2 = L >> 6; \
|
||||
tmp2 &= 0x3FC; \
|
||||
tmp3 = L >> 14; \
|
||||
tmp3 &= 0x3FC; \
|
||||
tmp4 = L >> 22; \
|
||||
tmp4 &= 0x3FC; \
|
||||
tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \
|
||||
tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \
|
||||
tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \
|
||||
tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \
|
||||
tmp3 ^= tmp2; \
|
||||
R ^= data.ctx.P[N + 1]; \
|
||||
tmp3 += tmp1; \
|
||||
R ^= tmp3;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Encrypt one block, BF_N is hardcoded here.
|
||||
*/
|
||||
#define BF_ENCRYPT \
|
||||
L ^= data.ctx.P[0]; \
|
||||
BF_ROUND(L, R, 0); \
|
||||
BF_ROUND(R, L, 1); \
|
||||
BF_ROUND(L, R, 2); \
|
||||
BF_ROUND(R, L, 3); \
|
||||
BF_ROUND(L, R, 4); \
|
||||
BF_ROUND(R, L, 5); \
|
||||
BF_ROUND(L, R, 6); \
|
||||
BF_ROUND(R, L, 7); \
|
||||
BF_ROUND(L, R, 8); \
|
||||
BF_ROUND(R, L, 9); \
|
||||
BF_ROUND(L, R, 10); \
|
||||
BF_ROUND(R, L, 11); \
|
||||
BF_ROUND(L, R, 12); \
|
||||
BF_ROUND(R, L, 13); \
|
||||
BF_ROUND(L, R, 14); \
|
||||
BF_ROUND(R, L, 15); \
|
||||
tmp4 = R; \
|
||||
R = L; \
|
||||
L = tmp4 ^ data.ctx.P[BF_N + 1];
|
||||
|
||||
#if BF_ASM
|
||||
#define BF_body() \
|
||||
_BF_body_r(&data.ctx);
|
||||
#else
|
||||
#define BF_body() \
|
||||
L = R = 0; \
|
||||
ptr = data.ctx.P; \
|
||||
do { \
|
||||
ptr += 2; \
|
||||
BF_ENCRYPT; \
|
||||
*(ptr - 2) = L; \
|
||||
*(ptr - 1) = R; \
|
||||
} while (ptr < &data.ctx.P[BF_N + 2]); \
|
||||
\
|
||||
ptr = data.ctx.S[0]; \
|
||||
do { \
|
||||
ptr += 2; \
|
||||
BF_ENCRYPT; \
|
||||
*(ptr - 2) = L; \
|
||||
*(ptr - 1) = R; \
|
||||
} while (ptr < &data.ctx.S[3][0xFF]);
|
||||
#endif
|
||||
|
||||
static void BF_set_key(const char *key, BF_key expanded, BF_key initial,
|
||||
unsigned char flags)
|
||||
{
|
||||
const char *ptr = key;
|
||||
unsigned int bug, i, j;
|
||||
BF_word safety, sign, diff, tmp[2];
|
||||
|
||||
/*
|
||||
* There was a sign extension bug in older revisions of this function. While
|
||||
* we would have liked to simply fix the bug and move on, we have to provide
|
||||
* a backwards compatibility feature (essentially the bug) for some systems and
|
||||
* a safety measure for some others. The latter is needed because for certain
|
||||
* multiple inputs to the buggy algorithm there exist easily found inputs to
|
||||
* the correct algorithm that produce the same hash. Thus, we optionally
|
||||
* deviate from the correct algorithm just enough to avoid such collisions.
|
||||
* While the bug itself affected the majority of passwords containing
|
||||
* characters with the 8th bit set (although only a percentage of those in a
|
||||
* collision-producing way), the anti-collision safety measure affects
|
||||
* only a subset of passwords containing the '\xff' character (not even all of
|
||||
* those passwords, just some of them). This character is not found in valid
|
||||
* UTF-8 sequences and is rarely used in popular 8-bit character encodings.
|
||||
* Thus, the safety measure is unlikely to cause much annoyance, and is a
|
||||
* reasonable tradeoff to use when authenticating against existing hashes that
|
||||
* are not reliably known to have been computed with the correct algorithm.
|
||||
*
|
||||
* We use an approach that tries to minimize side-channel leaks of password
|
||||
* information - that is, we mostly use fixed-cost bitwise operations instead
|
||||
* of branches or table lookups. (One conditional branch based on password
|
||||
* length remains. It is not part of the bug aftermath, though, and is
|
||||
* difficult and possibly unreasonable to avoid given the use of C strings by
|
||||
* the caller, which results in similar timing leaks anyway.)
|
||||
*
|
||||
* For actual implementation, we set an array index in the variable "bug"
|
||||
* (0 means no bug, 1 means sign extension bug emulation) and a flag in the
|
||||
* variable "safety" (bit 16 is set when the safety measure is requested).
|
||||
* Valid combinations of settings are:
|
||||
*
|
||||
* Prefix "$2a$": bug = 0, safety = 0x10000
|
||||
* Prefix "$2b$": bug = 0, safety = 0
|
||||
* Prefix "$2x$": bug = 1, safety = 0
|
||||
* Prefix "$2y$": bug = 0, safety = 0
|
||||
*/
|
||||
bug = (unsigned int)flags & 1;
|
||||
safety = ((BF_word)flags & 2) << 15;
|
||||
|
||||
sign = diff = 0;
|
||||
|
||||
for (i = 0; i < BF_N + 2; i++) {
|
||||
tmp[0] = tmp[1] = 0;
|
||||
for (j = 0; j < 4; j++) {
|
||||
tmp[0] <<= 8;
|
||||
tmp[0] |= (unsigned char)*ptr; /* correct */
|
||||
tmp[1] <<= 8;
|
||||
tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
|
||||
/*
|
||||
* Sign extension in the first char has no effect - nothing to overwrite yet,
|
||||
* and those extra 24 bits will be fully shifted out of the 32-bit word. For
|
||||
* chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
|
||||
* extension in tmp[1] occurs. Once this flag is set, it remains set.
|
||||
*/
|
||||
if (j)
|
||||
sign |= tmp[1] & 0x80;
|
||||
if (!*ptr)
|
||||
ptr = key;
|
||||
else
|
||||
ptr++;
|
||||
}
|
||||
diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
|
||||
|
||||
expanded[i] = tmp[bug];
|
||||
initial[i] = BF_init_state.P[i] ^ tmp[bug];
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, "diff" is zero iff the correct and buggy algorithms produced
|
||||
* exactly the same result. If so and if "sign" is non-zero, which indicates
|
||||
* that there was a non-benign sign extension, this means that we have a
|
||||
* collision between the correctly computed hash for this password and a set of
|
||||
* passwords that could be supplied to the buggy algorithm. Our safety measure
|
||||
* is meant to protect from such many-buggy to one-correct collisions, by
|
||||
* deviating from the correct algorithm in such cases. Let's check for this.
|
||||
*/
|
||||
diff |= diff >> 16; /* still zero iff exact match */
|
||||
diff &= 0xffff; /* ditto */
|
||||
diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
|
||||
sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
|
||||
sign &= ~diff & safety; /* action needed? */
|
||||
|
||||
/*
|
||||
* If we have determined that we need to deviate from the correct algorithm,
|
||||
* flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but
|
||||
* let's stick to it now. It came out of the approach we used above, and it's
|
||||
* not any worse than any other choice we could make.)
|
||||
*
|
||||
* It is crucial that we don't do the same to the expanded key used in the main
|
||||
* Eksblowfish loop. By doing it to only one of these two, we deviate from a
|
||||
* state that could be directly specified by a password to the buggy algorithm
|
||||
* (and to the fully correct one as well, but that's a side-effect).
|
||||
*/
|
||||
initial[0] ^= sign;
|
||||
}
|
||||
|
||||
static const unsigned char flags_by_subtype[26] =
|
||||
{2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
|
||||
|
||||
static char *BF_crypt(const char *key, const char *setting,
|
||||
char *output, int size,
|
||||
BF_word min)
|
||||
{
|
||||
#if BF_ASM
|
||||
extern void _BF_body_r(BF_ctx *ctx);
|
||||
#endif
|
||||
struct {
|
||||
BF_ctx ctx;
|
||||
BF_key expanded_key;
|
||||
union {
|
||||
BF_word salt[4];
|
||||
BF_word output[6];
|
||||
} binary;
|
||||
} data;
|
||||
BF_word L, R;
|
||||
BF_word tmp1, tmp2, tmp3, tmp4;
|
||||
BF_word *ptr;
|
||||
BF_word count;
|
||||
int i;
|
||||
|
||||
if (size < 7 + 22 + 31 + 1) {
|
||||
__set_errno(ERANGE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (setting[0] != '$' ||
|
||||
setting[1] != '2' ||
|
||||
setting[2] < 'a' || setting[2] > 'z' ||
|
||||
!flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
|
||||
setting[3] != '$' ||
|
||||
setting[4] < '0' || setting[4] > '3' ||
|
||||
setting[5] < '0' || setting[5] > '9' ||
|
||||
(setting[4] == '3' && setting[5] > '1') ||
|
||||
setting[6] != '$') {
|
||||
__set_errno(EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
|
||||
if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
|
||||
__set_errno(EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
BF_swap(data.binary.salt, 4);
|
||||
|
||||
BF_set_key(key, data.expanded_key, data.ctx.P,
|
||||
flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
|
||||
|
||||
memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
|
||||
|
||||
L = R = 0;
|
||||
for (i = 0; i < BF_N + 2; i += 2) {
|
||||
L ^= data.binary.salt[i & 2];
|
||||
R ^= data.binary.salt[(i & 2) + 1];
|
||||
BF_ENCRYPT;
|
||||
data.ctx.P[i] = L;
|
||||
data.ctx.P[i + 1] = R;
|
||||
}
|
||||
|
||||
ptr = data.ctx.S[0];
|
||||
do {
|
||||
ptr += 4;
|
||||
L ^= data.binary.salt[(BF_N + 2) & 3];
|
||||
R ^= data.binary.salt[(BF_N + 3) & 3];
|
||||
BF_ENCRYPT;
|
||||
*(ptr - 4) = L;
|
||||
*(ptr - 3) = R;
|
||||
|
||||
L ^= data.binary.salt[(BF_N + 4) & 3];
|
||||
R ^= data.binary.salt[(BF_N + 5) & 3];
|
||||
BF_ENCRYPT;
|
||||
*(ptr - 2) = L;
|
||||
*(ptr - 1) = R;
|
||||
} while (ptr < &data.ctx.S[3][0xFF]);
|
||||
|
||||
do {
|
||||
int done;
|
||||
|
||||
for (i = 0; i < BF_N + 2; i += 2) {
|
||||
data.ctx.P[i] ^= data.expanded_key[i];
|
||||
data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
|
||||
}
|
||||
|
||||
done = 0;
|
||||
do {
|
||||
BF_body();
|
||||
if (done)
|
||||
break;
|
||||
done = 1;
|
||||
|
||||
tmp1 = data.binary.salt[0];
|
||||
tmp2 = data.binary.salt[1];
|
||||
tmp3 = data.binary.salt[2];
|
||||
tmp4 = data.binary.salt[3];
|
||||
for (i = 0; i < BF_N; i += 4) {
|
||||
data.ctx.P[i] ^= tmp1;
|
||||
data.ctx.P[i + 1] ^= tmp2;
|
||||
data.ctx.P[i + 2] ^= tmp3;
|
||||
data.ctx.P[i + 3] ^= tmp4;
|
||||
}
|
||||
data.ctx.P[16] ^= tmp1;
|
||||
data.ctx.P[17] ^= tmp2;
|
||||
} while (1);
|
||||
} while (--count);
|
||||
|
||||
for (i = 0; i < 6; i += 2) {
|
||||
L = BF_magic_w[i];
|
||||
R = BF_magic_w[i + 1];
|
||||
|
||||
count = 64;
|
||||
do {
|
||||
BF_ENCRYPT;
|
||||
} while (--count);
|
||||
|
||||
data.binary.output[i] = L;
|
||||
data.binary.output[i + 1] = R;
|
||||
}
|
||||
|
||||
memcpy(output, setting, 7 + 22 - 1);
|
||||
output[7 + 22 - 1] = BF_itoa64[(int)
|
||||
BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];
|
||||
|
||||
/* This has to be bug-compatible with the original implementation, so
|
||||
* only encode 23 of the 24 bytes. :-) */
|
||||
BF_swap(data.binary.output, 6);
|
||||
BF_encode(&output[7 + 22], data.binary.output, 23);
|
||||
output[7 + 22 + 31] = '\0';
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
int _crypt_output_magic(const char *setting, char *output, int size)
|
||||
{
|
||||
if (size < 3)
|
||||
return -1;
|
||||
|
||||
output[0] = '*';
|
||||
output[1] = '0';
|
||||
output[2] = '\0';
|
||||
|
||||
if (setting[0] == '*' && setting[1] == '0')
|
||||
output[1] = '1';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Please preserve the runtime self-test. It serves two purposes at once:
|
||||
*
|
||||
* 1. We really can't afford the risk of producing incompatible hashes e.g.
|
||||
* when there's something like gcc bug 26587 again, whereas an application or
|
||||
* library integrating this code might not also integrate our external tests or
|
||||
* it might not run them after every build. Even if it does, the miscompile
|
||||
* might only occur on the production build, but not on a testing build (such
|
||||
* as because of different optimization settings). It is painful to recover
|
||||
* from incorrectly-computed hashes - merely fixing whatever broke is not
|
||||
* enough. Thus, a proactive measure like this self-test is needed.
|
||||
*
|
||||
* 2. We don't want to leave sensitive data from our actual password hash
|
||||
* computation on the stack or in registers. Previous revisions of the code
|
||||
* would do explicit cleanups, but simply running the self-test after hash
|
||||
* computation is more reliable.
|
||||
*
|
||||
* The performance cost of this quick self-test is around 0.6% at the "$2a$08"
|
||||
* setting.
|
||||
*/
|
||||
char *_crypt_blowfish_rn(const char *key, const char *setting,
|
||||
char *output, int size)
|
||||
{
|
||||
const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8";
|
||||
const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu";
|
||||
static const char * const test_hashes[2] =
|
||||
{"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */
|
||||
"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */
|
||||
const char *test_hash = test_hashes[0];
|
||||
char *retval;
|
||||
const char *p;
|
||||
int save_errno, ok;
|
||||
struct {
|
||||
char s[7 + 22 + 1];
|
||||
char o[7 + 22 + 31 + 1 + 1 + 1];
|
||||
} buf;
|
||||
|
||||
/* Hash the supplied password */
|
||||
_crypt_output_magic(setting, output, size);
|
||||
retval = BF_crypt(key, setting, output, size, 16);
|
||||
save_errno = errno;
|
||||
|
||||
/*
|
||||
* Do a quick self-test. It is important that we make both calls to BF_crypt()
|
||||
* from the same scope such that they likely use the same stack locations,
|
||||
* which makes the second call overwrite the first call's sensitive data on the
|
||||
* stack and makes it more likely that any alignment related issues would be
|
||||
* detected by the self-test.
|
||||
*/
|
||||
memcpy(buf.s, test_setting, sizeof(buf.s));
|
||||
if (retval) {
|
||||
unsigned int flags = flags_by_subtype[
|
||||
(unsigned int)(unsigned char)setting[2] - 'a'];
|
||||
test_hash = test_hashes[flags & 1];
|
||||
buf.s[2] = setting[2];
|
||||
}
|
||||
memset(buf.o, 0x55, sizeof(buf.o));
|
||||
buf.o[sizeof(buf.o) - 1] = 0;
|
||||
p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1);
|
||||
|
||||
ok = (p == buf.o &&
|
||||
!memcmp(p, buf.s, 7 + 22) &&
|
||||
!memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1));
|
||||
|
||||
{
|
||||
const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345";
|
||||
BF_key ae, ai, ye, yi;
|
||||
BF_set_key(k, ae, ai, 2); /* $2a$ */
|
||||
BF_set_key(k, ye, yi, 4); /* $2y$ */
|
||||
ai[0] ^= 0x10000; /* undo the safety (for comparison) */
|
||||
ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 &&
|
||||
!memcmp(ae, ye, sizeof(ae)) &&
|
||||
!memcmp(ai, yi, sizeof(ai));
|
||||
}
|
||||
|
||||
__set_errno(save_errno);
|
||||
if (ok)
|
||||
return retval;
|
||||
|
||||
/* Should not happen */
|
||||
_crypt_output_magic(setting, output, size);
|
||||
__set_errno(EINVAL); /* pretend we don't support this hash type */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
|
||||
const char *input, int size, char *output, int output_size)
|
||||
{
|
||||
if (size < 16 || output_size < 7 + 22 + 1 ||
|
||||
(count && (count < 4 || count > 31)) ||
|
||||
prefix[0] != '$' || prefix[1] != '2' ||
|
||||
(prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) {
|
||||
if (output_size > 0) output[0] = '\0';
|
||||
__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!count) count = 5;
|
||||
|
||||
output[0] = '$';
|
||||
output[1] = '2';
|
||||
output[2] = prefix[2];
|
||||
output[3] = '$';
|
||||
output[4] = '0' + count / 10;
|
||||
output[5] = '0' + count % 10;
|
||||
output[6] = '$';
|
||||
|
||||
BF_encode(&output[7], (const BF_word *)input, 16);
|
||||
output[7 + 22] = '\0';
|
||||
|
||||
return output;
|
||||
}
|
27
src/contrib/bcrypt/crypt_blowfish.h
Normal file
27
src/contrib/bcrypt/crypt_blowfish.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See crypt_blowfish.c for more information.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPT_BLOWFISH_H
|
||||
#define _CRYPT_BLOWFISH_H
|
||||
|
||||
extern int _crypt_output_magic(const char *setting, char *output, int size);
|
||||
extern char *_crypt_blowfish_rn(const char *key, const char *setting,
|
||||
char *output, int size);
|
||||
extern char *_crypt_gensalt_blowfish_rn(const char *prefix,
|
||||
unsigned long count,
|
||||
const char *input, int size, char *output, int output_size);
|
||||
|
||||
#endif
|
128
src/contrib/bcrypt/crypt_gensalt.c
Normal file
128
src/contrib/bcrypt/crypt_gensalt.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See crypt_blowfish.c for more information.
|
||||
*
|
||||
* This file contains salt generation functions for the traditional and
|
||||
* other common crypt(3) algorithms, except for bcrypt which is defined
|
||||
* entirely in crypt_blowfish.c.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef __set_errno
|
||||
#define __set_errno(val) errno = (val)
|
||||
#endif
|
||||
|
||||
/* Just to make sure the prototypes match the actual definitions */
|
||||
#ifdef _WIN32
|
||||
#include "crypt_gensalt.h"
|
||||
#else
|
||||
#include "crypt_gensalt.h"
|
||||
#endif
|
||||
|
||||
unsigned char _crypt_itoa64[64 + 1] =
|
||||
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
|
||||
const char *input, int size, char *output, int output_size)
|
||||
{
|
||||
(void) prefix;
|
||||
|
||||
if (size < 2 || output_size < 2 + 1 || (count && count != 25)) {
|
||||
if (output_size > 0) output[0] = '\0';
|
||||
__set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f];
|
||||
output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f];
|
||||
output[2] = '\0';
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count,
|
||||
const char *input, int size, char *output, int output_size)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
(void) prefix;
|
||||
|
||||
/* Even iteration counts make it easier to detect weak DES keys from a look
|
||||
* at the hash, so they should be avoided */
|
||||
if (size < 3 || output_size < 1 + 4 + 4 + 1 ||
|
||||
(count && (count > 0xffffff || !(count & 1)))) {
|
||||
if (output_size > 0) output[0] = '\0';
|
||||
__set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!count) count = 725;
|
||||
|
||||
output[0] = '_';
|
||||
output[1] = _crypt_itoa64[count & 0x3f];
|
||||
output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
|
||||
output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
|
||||
output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
|
||||
value = (unsigned long)(unsigned char)input[0] |
|
||||
((unsigned long)(unsigned char)input[1] << 8) |
|
||||
((unsigned long)(unsigned char)input[2] << 16);
|
||||
output[5] = _crypt_itoa64[value & 0x3f];
|
||||
output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
|
||||
output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
|
||||
output[8] = _crypt_itoa64[(value >> 18) & 0x3f];
|
||||
output[9] = '\0';
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
|
||||
const char *input, int size, char *output, int output_size)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
(void) prefix;
|
||||
|
||||
if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) {
|
||||
if (output_size > 0) output[0] = '\0';
|
||||
__set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output[0] = '$';
|
||||
output[1] = '1';
|
||||
output[2] = '$';
|
||||
value = (unsigned long)(unsigned char)input[0] |
|
||||
((unsigned long)(unsigned char)input[1] << 8) |
|
||||
((unsigned long)(unsigned char)input[2] << 16);
|
||||
output[3] = _crypt_itoa64[value & 0x3f];
|
||||
output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
|
||||
output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
|
||||
output[6] = _crypt_itoa64[(value >> 18) & 0x3f];
|
||||
output[7] = '\0';
|
||||
|
||||
if (size >= 6 && output_size >= 3 + 4 + 4 + 1) {
|
||||
value = (unsigned long)(unsigned char)input[3] |
|
||||
((unsigned long)(unsigned char)input[4] << 8) |
|
||||
((unsigned long)(unsigned char)input[5] << 16);
|
||||
output[7] = _crypt_itoa64[value & 0x3f];
|
||||
output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
|
||||
output[9] = _crypt_itoa64[(value >> 12) & 0x3f];
|
||||
output[10] = _crypt_itoa64[(value >> 18) & 0x3f];
|
||||
output[11] = '\0';
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
30
src/contrib/bcrypt/crypt_gensalt.h
Normal file
30
src/contrib/bcrypt/crypt_gensalt.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See crypt_blowfish.c for more information.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPT_GENSALT_H
|
||||
#define _CRYPT_GENSALT_H
|
||||
|
||||
extern unsigned char _crypt_itoa64[];
|
||||
extern char *_crypt_gensalt_traditional_rn(const char *prefix,
|
||||
unsigned long count,
|
||||
const char *input, int size, char *output, int output_size);
|
||||
extern char *_crypt_gensalt_extended_rn(const char *prefix,
|
||||
unsigned long count,
|
||||
const char *input, int size, char *output, int output_size);
|
||||
extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
|
||||
const char *input, int size, char *output, int output_size);
|
||||
|
||||
#endif
|
43
src/contrib/bcrypt/ow-crypt.h
Normal file
43
src/contrib/bcrypt/ow-crypt.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See crypt_blowfish.c for more information.
|
||||
*/
|
||||
|
||||
#ifndef _OW_CRYPT_H
|
||||
#define _OW_CRYPT_H
|
||||
|
||||
#ifndef __GNUC__
|
||||
#undef __const
|
||||
#define __const const
|
||||
#endif
|
||||
|
||||
#ifndef __SKIP_GNU
|
||||
extern char *crypt(__const char *key, __const char *setting);
|
||||
extern char *crypt_r(__const char *key, __const char *setting, void *data);
|
||||
#endif
|
||||
|
||||
#ifndef __SKIP_OW
|
||||
extern char *crypt_rn(__const char *key, __const char *setting,
|
||||
void *data, int size);
|
||||
extern char *crypt_ra(__const char *key, __const char *setting,
|
||||
void **data, int *size);
|
||||
extern char *crypt_gensalt(__const char *prefix, unsigned long count,
|
||||
__const char *input, int size);
|
||||
extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count,
|
||||
__const char *input, int size, char *output, int output_size);
|
||||
extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count,
|
||||
__const char *input, int size);
|
||||
#endif
|
||||
|
||||
#endif
|
27
src/contrib/bcrypt/winbcrypt.h
Normal file
27
src/contrib/bcrypt/winbcrypt.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef __WIN_BCRYPT__H
|
||||
#define __WIN_BCRYPT__H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "crypt_blowfish.h"
|
||||
#include "bcrypt.h"
|
||||
|
||||
class BCrypt {
|
||||
public:
|
||||
static std::string generateHash(const std::string & password, int workload = 12) {
|
||||
char salt[BCRYPT_HASHSIZE];
|
||||
char hash[BCRYPT_HASHSIZE];
|
||||
int ret;
|
||||
ret = bcrypt_gensalt(workload, salt);
|
||||
if (ret != 0)throw std::runtime_error{ "bcrypt: can not generate salt" };
|
||||
ret = bcrypt_hashpw(password.c_str(), salt, hash);
|
||||
if (ret != 0)throw std::runtime_error{ "bcrypt: can not generate hash" };
|
||||
return std::string{ hash };
|
||||
}
|
||||
|
||||
static bool validatePassword(const std::string & password, const std::string & hash) {
|
||||
return (bcrypt_checkpw(password.c_str(), hash.c_str()) == 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
563
src/contrib/bcrypt/wrapper.c
Normal file
563
src/contrib/bcrypt/wrapper.c
Normal file
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* Written by Solar Designer <solar at openwall.com> in 2000-2014.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See crypt_blowfish.c for more information.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef __set_errno
|
||||
#define __set_errno(val) errno = (val)
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#ifdef TEST_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1)
|
||||
#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
|
||||
|
||||
#if defined(__GLIBC__) && defined(_LIBC)
|
||||
#define __SKIP_GNU
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32 | _WIN64
|
||||
#include "ow-crypt.h"
|
||||
|
||||
#include "crypt_blowfish.h"
|
||||
#include "crypt_gensalt.h"
|
||||
#else
|
||||
#include "ow-crypt.h"
|
||||
|
||||
#include "crypt_blowfish.h"
|
||||
#include "crypt_gensalt.h"
|
||||
#endif
|
||||
|
||||
#if defined(__GLIBC__) && defined(_LIBC)
|
||||
/* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */
|
||||
#include "crypt.h"
|
||||
extern char *__md5_crypt_r(const char *key, const char *salt,
|
||||
char *buffer, int buflen);
|
||||
/* crypt-entry.c needs to be patched to define __des_crypt_r rather than
|
||||
* __crypt_r, and not define crypt_r and crypt at all */
|
||||
extern char *__des_crypt_r(const char *key, const char *salt,
|
||||
struct crypt_data *data);
|
||||
extern struct crypt_data _ufc_foobar;
|
||||
#endif
|
||||
|
||||
static int _crypt_data_alloc(void **data, int *size, int need)
|
||||
{
|
||||
void *updated;
|
||||
|
||||
if (*data && *size >= need) return 0;
|
||||
|
||||
updated = realloc(*data, need);
|
||||
|
||||
if (!updated) {
|
||||
#ifndef __GLIBC__
|
||||
/* realloc(3) on glibc sets errno, so we don't need to bother */
|
||||
__set_errno(ENOMEM);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__GLIBC__) && defined(_LIBC)
|
||||
if (need >= sizeof(struct crypt_data))
|
||||
((struct crypt_data *)updated)->initialized = 0;
|
||||
#endif
|
||||
|
||||
*data = updated;
|
||||
*size = need;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *_crypt_retval_magic(char *retval, const char *setting,
|
||||
char *output, int size)
|
||||
{
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (_crypt_output_magic(setting, output, size))
|
||||
return NULL; /* shouldn't happen */
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#if defined(__GLIBC__) && defined(_LIBC)
|
||||
/*
|
||||
* Applications may re-use the same instance of struct crypt_data without
|
||||
* resetting the initialized field in order to let crypt_r() skip some of
|
||||
* its initialization code. Thus, it is important that our multiple hashing
|
||||
* algorithms either don't conflict with each other in their use of the
|
||||
* data area or reset the initialized field themselves whenever required.
|
||||
* Currently, the hashing algorithms simply have no conflicts: the first
|
||||
* field of struct crypt_data is the 128-byte large DES key schedule which
|
||||
* __des_crypt_r() calculates each time it is called while the two other
|
||||
* hashing algorithms use less than 128 bytes of the data area.
|
||||
*/
|
||||
|
||||
char *__crypt_rn(__const char *key, __const char *setting,
|
||||
void *data, int size)
|
||||
{
|
||||
if (setting[0] == '$' && setting[1] == '2')
|
||||
return _crypt_blowfish_rn(key, setting, (char *)data, size);
|
||||
if (setting[0] == '$' && setting[1] == '1')
|
||||
return __md5_crypt_r(key, setting, (char *)data, size);
|
||||
if (setting[0] == '$' || setting[0] == '_') {
|
||||
__set_errno(EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
if (size >= sizeof(struct crypt_data))
|
||||
return __des_crypt_r(key, setting, (struct crypt_data *)data);
|
||||
__set_errno(ERANGE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *__crypt_ra(__const char *key, __const char *setting,
|
||||
void **data, int *size)
|
||||
{
|
||||
if (setting[0] == '$' && setting[1] == '2') {
|
||||
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
|
||||
return NULL;
|
||||
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
|
||||
}
|
||||
if (setting[0] == '$' && setting[1] == '1') {
|
||||
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
|
||||
return NULL;
|
||||
return __md5_crypt_r(key, setting, (char *)*data, *size);
|
||||
}
|
||||
if (setting[0] == '$' || setting[0] == '_') {
|
||||
__set_errno(EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
if (_crypt_data_alloc(data, size, sizeof(struct crypt_data)))
|
||||
return NULL;
|
||||
return __des_crypt_r(key, setting, (struct crypt_data *)*data);
|
||||
}
|
||||
|
||||
char *__crypt_r(__const char *key, __const char *setting,
|
||||
struct crypt_data *data)
|
||||
{
|
||||
return _crypt_retval_magic(
|
||||
__crypt_rn(key, setting, data, sizeof(*data)),
|
||||
setting, (char *)data, sizeof(*data));
|
||||
}
|
||||
|
||||
char *__crypt(__const char *key, __const char *setting)
|
||||
{
|
||||
return _crypt_retval_magic(
|
||||
__crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)),
|
||||
setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar));
|
||||
}
|
||||
#else
|
||||
char *crypt_rn(const char *key, const char *setting, void *data, int size)
|
||||
{
|
||||
return _crypt_blowfish_rn(key, setting, (char *)data, size);
|
||||
}
|
||||
|
||||
char *crypt_ra(const char *key, const char *setting,
|
||||
void **data, int *size)
|
||||
{
|
||||
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
|
||||
return NULL;
|
||||
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
|
||||
}
|
||||
|
||||
char *crypt_r(const char *key, const char *setting, void *data)
|
||||
{
|
||||
return _crypt_retval_magic(
|
||||
crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
|
||||
setting, (char *)data, CRYPT_OUTPUT_SIZE);
|
||||
}
|
||||
|
||||
char *crypt(const char *key, const char *setting)
|
||||
{
|
||||
static char output[CRYPT_OUTPUT_SIZE];
|
||||
|
||||
return _crypt_retval_magic(
|
||||
crypt_rn(key, setting, output, sizeof(output)),
|
||||
setting, output, sizeof(output));
|
||||
}
|
||||
|
||||
#define __crypt_gensalt_rn crypt_gensalt_rn
|
||||
#define __crypt_gensalt_ra crypt_gensalt_ra
|
||||
#define __crypt_gensalt crypt_gensalt
|
||||
#endif
|
||||
|
||||
char *__crypt_gensalt_rn(const char *prefix, unsigned long count,
|
||||
const char *input, int size, char *output, int output_size)
|
||||
{
|
||||
char *(*use)(const char *_prefix, unsigned long _count,
|
||||
const char *_input, int _size,
|
||||
char *_output, int _output_size);
|
||||
|
||||
/* This may be supported on some platforms in the future */
|
||||
if (!input) {
|
||||
__set_errno(EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) ||
|
||||
!strncmp(prefix, "$2y$", 4))
|
||||
use = _crypt_gensalt_blowfish_rn;
|
||||
else
|
||||
if (!strncmp(prefix, "$1$", 3))
|
||||
use = _crypt_gensalt_md5_rn;
|
||||
else
|
||||
if (prefix[0] == '_')
|
||||
use = _crypt_gensalt_extended_rn;
|
||||
else
|
||||
if (!prefix[0] ||
|
||||
(prefix[0] && prefix[1] &&
|
||||
memchr(_crypt_itoa64, prefix[0], 64) &&
|
||||
memchr(_crypt_itoa64, prefix[1], 64)))
|
||||
use = _crypt_gensalt_traditional_rn;
|
||||
else {
|
||||
__set_errno(EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return use(prefix, count, input, size, output, output_size);
|
||||
}
|
||||
|
||||
char *__crypt_gensalt_ra(const char *prefix, unsigned long count,
|
||||
const char *input, int size)
|
||||
{
|
||||
char output[CRYPT_GENSALT_OUTPUT_SIZE];
|
||||
char *retval;
|
||||
|
||||
retval = __crypt_gensalt_rn(prefix, count,
|
||||
input, size, output, sizeof(output));
|
||||
|
||||
if (retval) {
|
||||
#ifdef _WIN32 | _WIN64
|
||||
retval = _strdup(retval);
|
||||
#else
|
||||
retval = strdup(retval);
|
||||
#endif
|
||||
#ifndef __GLIBC__
|
||||
/* strdup(3) on glibc sets errno, so we don't need to bother */
|
||||
if (!retval)
|
||||
__set_errno(ENOMEM);
|
||||
#endif
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
char *__crypt_gensalt(const char *prefix, unsigned long count,
|
||||
const char *input, int size)
|
||||
{
|
||||
static char output[CRYPT_GENSALT_OUTPUT_SIZE];
|
||||
|
||||
return __crypt_gensalt_rn(prefix, count,
|
||||
input, size, output, sizeof(output));
|
||||
}
|
||||
|
||||
#if defined(__GLIBC__) && defined(_LIBC)
|
||||
weak_alias(__crypt_rn, crypt_rn)
|
||||
weak_alias(__crypt_ra, crypt_ra)
|
||||
weak_alias(__crypt_r, crypt_r)
|
||||
weak_alias(__crypt, crypt)
|
||||
weak_alias(__crypt_gensalt_rn, crypt_gensalt_rn)
|
||||
weak_alias(__crypt_gensalt_ra, crypt_gensalt_ra)
|
||||
weak_alias(__crypt_gensalt, crypt_gensalt)
|
||||
weak_alias(crypt, fcrypt)
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
static const char *tests[][3] = {
|
||||
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW",
|
||||
"U*U"},
|
||||
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK",
|
||||
"U*U*"},
|
||||
{"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a",
|
||||
"U*U*U"},
|
||||
{"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
|
||||
"0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
"chars after 72 are ignored"},
|
||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
|
||||
"\xa3"},
|
||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
|
||||
"\xff\xff\xa3"},
|
||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
|
||||
"\xff\xff\xa3"},
|
||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.",
|
||||
"\xff\xff\xa3"},
|
||||
{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
|
||||
"\xff\xff\xa3"},
|
||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
|
||||
"\xa3"},
|
||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
|
||||
"\xa3"},
|
||||
{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
|
||||
"\xa3"},
|
||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
|
||||
"1\xa3" "345"},
|
||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
|
||||
"\xff\xa3" "345"},
|
||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
|
||||
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
|
||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
|
||||
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
|
||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.",
|
||||
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
|
||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
|
||||
"\xff\xa3" "345"},
|
||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
|
||||
"\xff\xa3" "345"},
|
||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
|
||||
"\xa3" "ab"},
|
||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
|
||||
"\xa3" "ab"},
|
||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
|
||||
"\xa3" "ab"},
|
||||
{"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS",
|
||||
"\xd1\x91"},
|
||||
{"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS",
|
||||
"\xd0\xc1\xd2\xcf\xcc\xd8"},
|
||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"chars after 72 are ignored as usual"},
|
||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
|
||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"},
|
||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
|
||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"},
|
||||
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
|
||||
""},
|
||||
{"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."},
|
||||
{"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."},
|
||||
{"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."},
|
||||
{"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."},
|
||||
{"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."},
|
||||
{"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."},
|
||||
{"*1", "", "*0"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
#define which tests[0]
|
||||
|
||||
static volatile sig_atomic_t running;
|
||||
|
||||
static void handle_timer(int signum)
|
||||
{
|
||||
(void) signum;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
static void *run(void *arg)
|
||||
{
|
||||
unsigned long count = 0;
|
||||
int i = 0;
|
||||
void *data = NULL;
|
||||
int size = 0x12345678;
|
||||
|
||||
do {
|
||||
const char *hash = tests[i][0];
|
||||
const char *key = tests[i][1];
|
||||
const char *setting = tests[i][2];
|
||||
|
||||
if (!tests[++i][0])
|
||||
i = 0;
|
||||
|
||||
if (setting && strlen(hash) < 30) /* not for benchmark */
|
||||
continue;
|
||||
|
||||
if (strcmp(crypt_ra(key, hash, &data, &size), hash)) {
|
||||
printf("%d: FAILED (crypt_ra/%d/%lu)\n",
|
||||
(int)((char *)arg - (char *)0), i, count);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
count++;
|
||||
} while (running);
|
||||
|
||||
free(data);
|
||||
return count + (char *)0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct itimerval it;
|
||||
struct tms buf;
|
||||
clock_t clk_tck, start_real, start_virtual, end_real, end_virtual;
|
||||
unsigned long count;
|
||||
void *data;
|
||||
int size;
|
||||
char *setting1, *setting2;
|
||||
int i;
|
||||
#ifdef TEST_THREADS
|
||||
pthread_t t[TEST_THREADS];
|
||||
void *t_retval;
|
||||
#endif
|
||||
|
||||
data = NULL;
|
||||
size = 0x12345678;
|
||||
|
||||
for (i = 0; tests[i][0]; i++) {
|
||||
const char *hash = tests[i][0];
|
||||
const char *key = tests[i][1];
|
||||
const char *setting = tests[i][2];
|
||||
const char *p;
|
||||
int ok = !setting || strlen(hash) >= 30;
|
||||
int o_size;
|
||||
char s_buf[30], o_buf[61];
|
||||
if (!setting) {
|
||||
memcpy(s_buf, hash, sizeof(s_buf) - 1);
|
||||
s_buf[sizeof(s_buf) - 1] = 0;
|
||||
setting = s_buf;
|
||||
}
|
||||
|
||||
__set_errno(0);
|
||||
p = crypt(key, setting);
|
||||
if ((!ok && !errno) || strcmp(p, hash)) {
|
||||
printf("FAILED (crypt/%d)\n", i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ok && strcmp(crypt(key, hash), hash)) {
|
||||
printf("FAILED (crypt/%d)\n", i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) {
|
||||
int ok_n = ok && o_size == (int)sizeof(o_buf);
|
||||
const char *x = "abc";
|
||||
strcpy(o_buf, x);
|
||||
if (o_size >= 3) {
|
||||
x = "*0";
|
||||
if (setting[0] == '*' && setting[1] == '0')
|
||||
x = "*1";
|
||||
}
|
||||
__set_errno(0);
|
||||
p = crypt_rn(key, setting, o_buf, o_size);
|
||||
if ((ok_n && (!p || strcmp(p, hash))) ||
|
||||
(!ok_n && (!errno || p || strcmp(o_buf, x)))) {
|
||||
printf("FAILED (crypt_rn/%d)\n", i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
__set_errno(0);
|
||||
p = crypt_ra(key, setting, &data, &size);
|
||||
if ((ok && (!p || strcmp(p, hash))) ||
|
||||
(!ok && (!errno || p || strcmp((char *)data, hash)))) {
|
||||
printf("FAILED (crypt_ra/%d)\n", i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
setting1 = crypt_gensalt(which[0], 12, data, size);
|
||||
if (!setting1 || strncmp(setting1, "$2a$12$", 7)) {
|
||||
puts("FAILED (crypt_gensalt)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
setting2 = crypt_gensalt_ra(setting1, 12, data, size);
|
||||
if (strcmp(setting1, setting2)) {
|
||||
puts("FAILED (crypt_gensalt_ra/1)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
(*(char *)data)++;
|
||||
setting1 = crypt_gensalt_ra(setting2, 12, data, size);
|
||||
if (!strcmp(setting1, setting2)) {
|
||||
puts("FAILED (crypt_gensalt_ra/2)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(setting1);
|
||||
free(setting2);
|
||||
free(data);
|
||||
|
||||
#if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
|
||||
clk_tck = sysconf(_SC_CLK_TCK);
|
||||
#else
|
||||
clk_tck = CLK_TCK;
|
||||
#endif
|
||||
|
||||
running = 1;
|
||||
signal(SIGALRM, handle_timer);
|
||||
|
||||
memset(&it, 0, sizeof(it));
|
||||
it.it_value.tv_sec = 5;
|
||||
setitimer(ITIMER_REAL, &it, NULL);
|
||||
|
||||
start_real = times(&buf);
|
||||
start_virtual = buf.tms_utime + buf.tms_stime;
|
||||
|
||||
count = (char *)run((char *)0) - (char *)0;
|
||||
|
||||
end_real = times(&buf);
|
||||
end_virtual = buf.tms_utime + buf.tms_stime;
|
||||
if (end_virtual == start_virtual) end_virtual++;
|
||||
|
||||
printf("%.1f c/s real, %.1f c/s virtual\n",
|
||||
(float)count * clk_tck / (end_real - start_real),
|
||||
(float)count * clk_tck / (end_virtual - start_virtual));
|
||||
|
||||
#ifdef TEST_THREADS
|
||||
running = 1;
|
||||
it.it_value.tv_sec = 60;
|
||||
setitimer(ITIMER_REAL, &it, NULL);
|
||||
start_real = times(&buf);
|
||||
|
||||
for (i = 0; i < TEST_THREADS; i++)
|
||||
if (pthread_create(&t[i], NULL, run, i + (char *)0)) {
|
||||
perror("pthread_create");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < TEST_THREADS; i++) {
|
||||
if (pthread_join(t[i], &t_retval)) {
|
||||
perror("pthread_join");
|
||||
continue;
|
||||
}
|
||||
if (!t_retval) continue;
|
||||
count = (char *)t_retval - (char *)0;
|
||||
end_real = times(&buf);
|
||||
printf("%d: %.1f c/s real\n", i,
|
||||
(float)count * clk_tck / (end_real - start_real));
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
202
src/contrib/bcrypt/x86.S
Normal file
202
src/contrib/bcrypt/x86.S
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Written by Solar Designer <solar at openwall.com> in 1998-2010.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 1998-2010 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See crypt_blowfish.c for more information.
|
||||
*/
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#if defined(__OpenBSD__) && !defined(__ELF__)
|
||||
#define UNDERSCORES
|
||||
#define ALIGN_LOG
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN32__) || defined(__MINGW32__)
|
||||
#define UNDERSCORES
|
||||
#endif
|
||||
|
||||
#ifdef __DJGPP__
|
||||
#define UNDERSCORES
|
||||
#define ALIGN_LOG
|
||||
#endif
|
||||
|
||||
#ifdef UNDERSCORES
|
||||
#define _BF_body_r __BF_body_r
|
||||
#endif
|
||||
|
||||
#ifdef ALIGN_LOG
|
||||
#define DO_ALIGN(log) .align (log)
|
||||
#elif defined(DUMBAS)
|
||||
#define DO_ALIGN(log) .align 1 << log
|
||||
#else
|
||||
#define DO_ALIGN(log) .align (1 << (log))
|
||||
#endif
|
||||
|
||||
#define BF_FRAME 0x200
|
||||
#define ctx %esp
|
||||
|
||||
#define BF_ptr (ctx)
|
||||
|
||||
#define S(N, r) N+BF_FRAME(ctx,r,4)
|
||||
#ifdef DUMBAS
|
||||
#define P(N) 0x1000+N+N+N+N+BF_FRAME(ctx)
|
||||
#else
|
||||
#define P(N) 0x1000+4*N+BF_FRAME(ctx)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This version of the assembly code is optimized primarily for the original
|
||||
* Intel Pentium but is also careful to avoid partial register stalls on the
|
||||
* Pentium Pro family of processors (tested up to Pentium III Coppermine).
|
||||
*
|
||||
* It is possible to do 15% faster on the Pentium Pro family and probably on
|
||||
* many non-Intel x86 processors, but, unfortunately, that would make things
|
||||
* twice slower for the original Pentium.
|
||||
*
|
||||
* An additional 2% speedup may be achieved with non-reentrant code.
|
||||
*/
|
||||
|
||||
#define L %esi
|
||||
#define R %edi
|
||||
#define tmp1 %eax
|
||||
#define tmp1_lo %al
|
||||
#define tmp2 %ecx
|
||||
#define tmp2_hi %ch
|
||||
#define tmp3 %edx
|
||||
#define tmp3_lo %dl
|
||||
#define tmp4 %ebx
|
||||
#define tmp4_hi %bh
|
||||
#define tmp5 %ebp
|
||||
|
||||
.text
|
||||
|
||||
#define BF_ROUND(L, R, N) \
|
||||
xorl L,tmp2; \
|
||||
xorl tmp1,tmp1; \
|
||||
movl tmp2,L; \
|
||||
shrl $16,tmp2; \
|
||||
movl L,tmp4; \
|
||||
movb tmp2_hi,tmp1_lo; \
|
||||
andl $0xFF,tmp2; \
|
||||
movb tmp4_hi,tmp3_lo; \
|
||||
andl $0xFF,tmp4; \
|
||||
movl S(0,tmp1),tmp1; \
|
||||
movl S(0x400,tmp2),tmp5; \
|
||||
addl tmp5,tmp1; \
|
||||
movl S(0x800,tmp3),tmp5; \
|
||||
xorl tmp5,tmp1; \
|
||||
movl S(0xC00,tmp4),tmp5; \
|
||||
addl tmp1,tmp5; \
|
||||
movl 4+P(N),tmp2; \
|
||||
xorl tmp5,R
|
||||
|
||||
#define BF_ENCRYPT_START \
|
||||
BF_ROUND(L, R, 0); \
|
||||
BF_ROUND(R, L, 1); \
|
||||
BF_ROUND(L, R, 2); \
|
||||
BF_ROUND(R, L, 3); \
|
||||
BF_ROUND(L, R, 4); \
|
||||
BF_ROUND(R, L, 5); \
|
||||
BF_ROUND(L, R, 6); \
|
||||
BF_ROUND(R, L, 7); \
|
||||
BF_ROUND(L, R, 8); \
|
||||
BF_ROUND(R, L, 9); \
|
||||
BF_ROUND(L, R, 10); \
|
||||
BF_ROUND(R, L, 11); \
|
||||
BF_ROUND(L, R, 12); \
|
||||
BF_ROUND(R, L, 13); \
|
||||
BF_ROUND(L, R, 14); \
|
||||
BF_ROUND(R, L, 15); \
|
||||
movl BF_ptr,tmp5; \
|
||||
xorl L,tmp2; \
|
||||
movl P(17),L
|
||||
|
||||
#define BF_ENCRYPT_END \
|
||||
xorl R,L; \
|
||||
movl tmp2,R
|
||||
|
||||
DO_ALIGN(5)
|
||||
.globl _BF_body_r
|
||||
_BF_body_r:
|
||||
movl 4(%esp),%eax
|
||||
pushl %ebp
|
||||
pushl %ebx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
subl $BF_FRAME-8,%eax
|
||||
xorl L,L
|
||||
cmpl %esp,%eax
|
||||
ja BF_die
|
||||
xchgl %eax,%esp
|
||||
xorl R,R
|
||||
pushl %eax
|
||||
leal 0x1000+BF_FRAME-4(ctx),%eax
|
||||
movl 0x1000+BF_FRAME-4(ctx),tmp2
|
||||
pushl %eax
|
||||
xorl tmp3,tmp3
|
||||
BF_loop_P:
|
||||
BF_ENCRYPT_START
|
||||
addl $8,tmp5
|
||||
BF_ENCRYPT_END
|
||||
leal 0x1000+18*4+BF_FRAME(ctx),tmp1
|
||||
movl tmp5,BF_ptr
|
||||
cmpl tmp5,tmp1
|
||||
movl L,-8(tmp5)
|
||||
movl R,-4(tmp5)
|
||||
movl P(0),tmp2
|
||||
ja BF_loop_P
|
||||
leal BF_FRAME(ctx),tmp5
|
||||
xorl tmp3,tmp3
|
||||
movl tmp5,BF_ptr
|
||||
BF_loop_S:
|
||||
BF_ENCRYPT_START
|
||||
BF_ENCRYPT_END
|
||||
movl P(0),tmp2
|
||||
movl L,(tmp5)
|
||||
movl R,4(tmp5)
|
||||
BF_ENCRYPT_START
|
||||
BF_ENCRYPT_END
|
||||
movl P(0),tmp2
|
||||
movl L,8(tmp5)
|
||||
movl R,12(tmp5)
|
||||
BF_ENCRYPT_START
|
||||
BF_ENCRYPT_END
|
||||
movl P(0),tmp2
|
||||
movl L,16(tmp5)
|
||||
movl R,20(tmp5)
|
||||
BF_ENCRYPT_START
|
||||
addl $32,tmp5
|
||||
BF_ENCRYPT_END
|
||||
leal 0x1000+BF_FRAME(ctx),tmp1
|
||||
movl tmp5,BF_ptr
|
||||
cmpl tmp5,tmp1
|
||||
movl P(0),tmp2
|
||||
movl L,-8(tmp5)
|
||||
movl R,-4(tmp5)
|
||||
ja BF_loop_S
|
||||
movl 4(%esp),%esp
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
BF_die:
|
||||
/* Oops, need to re-compile with a larger BF_FRAME. */
|
||||
hlt
|
||||
jmp BF_die
|
||||
|
||||
#if defined(__ELF__) && defined(__linux__)
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
#endif
|
230517
src/contrib/sqlite/sqlite3.c
Normal file
230517
src/contrib/sqlite/sqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
12174
src/contrib/sqlite/sqlite3.h
Normal file
12174
src/contrib/sqlite/sqlite3.h
Normal file
File diff suppressed because it is too large
Load Diff
13348
src/contrib/sqlite/sqlite_orm.h
Normal file
13348
src/contrib/sqlite/sqlite_orm.h
Normal file
File diff suppressed because it is too large
Load Diff
84
src/main.cpp
84
src/main.cpp
@@ -2,46 +2,98 @@
|
||||
#include "CNShardServer.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "ChatManager.hpp"
|
||||
#include "CombatManager.hpp"
|
||||
#include "ItemManager.hpp"
|
||||
#include "MissionManager.hpp"
|
||||
#include "NanoManager.hpp"
|
||||
#include "NPCManager.hpp"
|
||||
#include "TransportManager.hpp"
|
||||
#include "Database.hpp"
|
||||
|
||||
#include "settings.hpp"
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
|
||||
#include "mingw/mingw.thread.h"
|
||||
#else
|
||||
#include <thread>
|
||||
#include <thread>
|
||||
#endif
|
||||
#include <string>
|
||||
#include <signal.h>
|
||||
|
||||
void startLogin(uint16_t port) {
|
||||
CNLoginServer server(port);
|
||||
server.start();
|
||||
CNShardServer *shardServer;
|
||||
std::thread *shardThread;
|
||||
|
||||
void startShard(CNShardServer* server) {
|
||||
server->start();
|
||||
}
|
||||
|
||||
void startShard(uint16_t port) {
|
||||
CNShardServer server(port);
|
||||
server.start();
|
||||
#ifndef _WIN32
|
||||
// terminate gracefully on SIGINT (for gprof)
|
||||
void terminate(int arg) {
|
||||
std::cout << "OpenFusion: terminating." << std::endl;
|
||||
shardServer->kill();
|
||||
shardThread->join();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void initsignals() {
|
||||
struct sigaction act;
|
||||
|
||||
memset((void*)&act, 0, sizeof(act));
|
||||
sigemptyset(&act.sa_mask);
|
||||
|
||||
// tell the OS to not kill us if you use a broken pipe, just let us know thru recv() or send()
|
||||
act.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGPIPE, &act, NULL) < 0) {
|
||||
perror("sigaction");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
act.sa_handler = terminate;
|
||||
if (sigaction(SIGINT, &act, NULL) < 0) {
|
||||
perror("sigaction");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
|
||||
std::cerr << "OpenFusion: WSAStartup failed" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
|
||||
std::cerr << "OpenFusion: WSAStartup failed" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
initsignals();
|
||||
#endif
|
||||
settings::init();
|
||||
std::cout << "[INFO] Protocol version: " << PROTOCOL_VERSION << std::endl;
|
||||
std::cout << "[INFO] Intializing Packet Managers..." << std::endl;
|
||||
PlayerManager::init();
|
||||
ChatManager::init();
|
||||
CombatManager::init();
|
||||
ItemManager::init();
|
||||
MissionManager::init();
|
||||
NanoManager::init();
|
||||
NPCManager::init();
|
||||
TransportManager::init();
|
||||
|
||||
Database::open();
|
||||
|
||||
std::cout << "[INFO] Starting Server Threads..." << std::endl;
|
||||
std::thread loginThread(startLogin, settings::LOGINPORT);
|
||||
std::thread shardThread(startShard, settings::SHARDPORT);
|
||||
getchar(); // blocks until input
|
||||
|
||||
CNLoginServer loginServer(settings::LOGINPORT);
|
||||
shardServer = new CNShardServer(settings::SHARDPORT);
|
||||
|
||||
shardThread = new std::thread(startShard, (CNShardServer*)shardServer);
|
||||
|
||||
loginServer.start();
|
||||
|
||||
shardServer->kill();
|
||||
shardThread->join();
|
||||
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -1,20 +1,29 @@
|
||||
#include <iostream>
|
||||
#include "settings.hpp"
|
||||
#include "INIReader.hpp"
|
||||
#include "contrib/INIReader.hpp"
|
||||
|
||||
// defaults :)
|
||||
int settings::VERBOSITY = 1;
|
||||
|
||||
int settings::LOGINPORT = 8001;
|
||||
bool settings::LOGINRANDCHARACTERS = false;
|
||||
bool settings::APPROVEALLNAMES = true;
|
||||
|
||||
int settings::SHARDPORT = 8002;
|
||||
std::string settings::SHARDSERVERIP = "127.0.0.1";
|
||||
int settings::VIEWDISTANCE = 25000;
|
||||
int settings::PLAYERDISTANCE = 20000;
|
||||
int settings::NPCDISTANCE = 16000;
|
||||
|
||||
// default spawn point is city hall
|
||||
int settings::SPAWN_X = 179213;
|
||||
int settings::SPAWN_Y = 268451;
|
||||
int settings::SPAWN_Z = -4210;
|
||||
|
||||
std::string settings::GMPASS = "pass";
|
||||
std::string settings::NPCJSON = "data/NPCs.json";
|
||||
std::string settings::WARPJSON = "data/warps.json";
|
||||
std::string settings::MOBJSON = "data/mobs.json";
|
||||
std::string settings::MOTDSTRING = "Welcome to OpenFusion!";
|
||||
bool settings::GM = false;
|
||||
|
||||
void settings::init() {
|
||||
INIReader reader("config.ini");
|
||||
@@ -28,13 +37,21 @@ void settings::init() {
|
||||
return;
|
||||
}
|
||||
|
||||
APPROVEALLNAMES = reader.GetBoolean("", "acceptallcustomnames", APPROVEALLNAMES);
|
||||
VERBOSITY = reader.GetInteger("", "verbosity", VERBOSITY);
|
||||
LOGINPORT = reader.GetInteger("login", "port", LOGINPORT);
|
||||
LOGINRANDCHARACTERS = reader.GetBoolean("login", "randomcharacters", LOGINRANDCHARACTERS);
|
||||
SHARDPORT = reader.GetInteger("shard", "port", SHARDPORT);
|
||||
SHARDSERVERIP = reader.Get("shard", "ip", "127.0.0.1");
|
||||
VIEWDISTANCE = reader.GetInteger("shard", "view", VIEWDISTANCE);
|
||||
PLAYERDISTANCE = reader.GetInteger("shard", "playerdistance", PLAYERDISTANCE);
|
||||
NPCDISTANCE = reader.GetInteger("shard", "npcdistance", NPCDISTANCE);
|
||||
SPAWN_X = reader.GetInteger("shard", "spawnx", SPAWN_X);
|
||||
SPAWN_Y = reader.GetInteger("shard", "spawny", SPAWN_Y);
|
||||
SPAWN_Z = reader.GetInteger("shard", "spawnz", SPAWN_Z);
|
||||
|
||||
}
|
||||
GMPASS = reader.Get("login", "pass", GMPASS);
|
||||
NPCJSON = reader.Get("shard", "npcdata", NPCJSON);
|
||||
WARPJSON = reader.Get("shard", "warpdata", WARPJSON);
|
||||
MOBJSON = reader.Get("shard", "mobdata", MOBJSON);
|
||||
MOTDSTRING = reader.Get("shard", "motd", MOTDSTRING);
|
||||
GM = reader.GetBoolean("shard", "gm", GM);
|
||||
}
|
||||
|
@@ -1,17 +1,23 @@
|
||||
#ifndef _SETT_HPP
|
||||
#define _SETT_HPP
|
||||
#pragma once
|
||||
|
||||
namespace settings {
|
||||
extern int VERBOSITY;
|
||||
extern int LOGINPORT;
|
||||
extern bool LOGINRANDCHARACTERS;
|
||||
extern bool APPROVEALLNAMES;
|
||||
extern int SHARDPORT;
|
||||
extern std::string SHARDSERVERIP;
|
||||
extern int VIEWDISTANCE;
|
||||
extern int PLAYERDISTANCE;
|
||||
extern int NPCDISTANCE;
|
||||
extern int SPAWN_X;
|
||||
extern int SPAWN_Y;
|
||||
extern int SPAWN_Z;
|
||||
extern std::string MOTDSTRING;
|
||||
extern std::string NPCJSON;
|
||||
extern std::string WARPJSON;
|
||||
extern std::string MOBJSON;
|
||||
extern std::string GMPASS;
|
||||
extern bool GM;
|
||||
|
||||
void init();
|
||||
}
|
||||
|
||||
#endif
|
4843
src/structs/0104.hpp
Normal file
4843
src/structs/0104.hpp
Normal file
File diff suppressed because it is too large
Load Diff
4885
src/structs/0728.hpp
Normal file
4885
src/structs/0728.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user