diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 68630aed627..f19ae6b80d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: # gcc, clang-8, clang-9 removed for reduce number of jobs @@ -58,7 +58,7 @@ jobs: CC: ${{ matrix.CC }} CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} --enable-epoll steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/clang15_test.yml b/.github/workflows/clang15_test.yml index b0808c64090..3096f8284ea 100644 --- a/.github/workflows/clang15_test.yml +++ b/.github/workflows/clang15_test.yml @@ -12,7 +12,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: [clang-15] @@ -62,7 +62,7 @@ jobs: CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} CPPFLAGS=${{ matrix.CLASSIC_AUTOSPELL_LIST }} PACKET_VERSION: ${{ matrix.PACKET_VERSION }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b13f58b3276..206cb5505dc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -31,14 +31,14 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/controller.yml b/.github/workflows/controller.yml index 1eeebf5d317..2b5cc80f00d 100644 --- a/.github/workflows/controller.yml +++ b/.github/workflows/controller.yml @@ -35,10 +35,6 @@ jobs: needs: build if: ${{ !failure() && !cancelled() }} uses: ./.github/workflows/gccold2.yml - gccold3: - needs: build - if: ${{ !failure() && !cancelled() }} - uses: ./.github/workflows/gccold3.yml gccsnapshot_test: needs: build if: ${{ !failure() && !cancelled() }} diff --git a/.github/workflows/gcc_test.yml b/.github/workflows/gcc_test.yml index 326fc9535c7..94485687ab1 100644 --- a/.github/workflows/gcc_test.yml +++ b/.github/workflows/gcc_test.yml @@ -12,7 +12,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: [gcc] @@ -62,7 +62,7 @@ jobs: CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} --enable-lto CPPFLAGS=${{ matrix.CLASSIC_AUTOSPELL_LIST }} PACKET_VERSION: ${{ matrix.PACKET_VERSION }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/gccold1.yml b/.github/workflows/gccold1.yml index 6dd3e6455e2..f1b23e3eece 100644 --- a/.github/workflows/gccold1.yml +++ b/.github/workflows/gccold1.yml @@ -12,7 +12,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: ["gcc-10", "gcc-9"] @@ -58,7 +58,7 @@ jobs: CC: ${{ matrix.CC }} CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} --enable-epoll CPPFLAGS=${{ matrix.CLASSIC_AUTOSPELL_LIST }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/gccold2.yml b/.github/workflows/gccold2.yml index 3a1f096dd5c..2a50aa94426 100644 --- a/.github/workflows/gccold2.yml +++ b/.github/workflows/gccold2.yml @@ -12,7 +12,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: ["gcc-8", "gcc-7"] @@ -58,7 +58,7 @@ jobs: CC: ${{ matrix.CC }} CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} --enable-epoll CPPFLAGS=${{ matrix.CLASSIC_AUTOSPELL_LIST }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/gccold3.yml b/.github/workflows/gccold3.yml deleted file mode 100644 index c5a17e4373e..00000000000 --- a/.github/workflows/gccold3.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: gcc_old3 - -on: workflow_call - -env: - MYSQL_DATABASE: 'ragnarok' - MYSQL_USER: 'ragnarok' - MYSQL_PASSWORD: 'ragnarok' - MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' - DEBIAN_COMMON_PACKAGES: make zlib1g-dev libpcre3-dev git python3 libzstd-dev - SKIP_VALIDATE_INTERFACES: "skip" - -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 60 - strategy: - matrix: - CC: ["gcc-6", "gcc-5", "gcc-4.8"] - RENEWAL: [""] - CLIENT_TYPE: ["", "--enable-packetver-re", "--enable-packetver-zero"] - HTTPLIB: ["", "--with-http_parser=llhttp"] - SANITIZER: ["--disable-manager --enable-sanitize=full"] - PACKET_VERSION: ["--enable-packetver=20100105", "--enable-packetver=20171018"] - LTO: [""] - include: - # Use "-DCLASSIC_AUTOSPELL_LIST" for all packetver or we will get warnings due to the list being too small (since they are old) - - CLASSIC_AUTOSPELL_LIST: "-DCLASSIC_AUTOSPELL_LIST" - exclude: - - PACKET_VERSION: "--enable-packetver=20100105" - CLIENT_TYPE: "--enable-packetver-zero" - - # github.head_ref will stop previous runs in the same PR (if in a PR) - # github.run_id is a fallback when outside a PR (e.g. every merge in master will run, and previous won't stop) - concurrency: - group: gccold3-${{ github.head_ref || github.run_id }}_${{ matrix.CC }}_${{ matrix.RENEWAL }}_${{ matrix.CLIENT_TYPE }}_${{ matrix.HTTPLIB }}_${{ matrix.SANITIZER }}_${{ matrix.PACKET_VERSION}}_${{ matrix.LTO }} - cancel-in-progress: true - - container: - image: ubuntu:18.04 - services: - mariadb: - image: mariadb:latest - ports: - - 33306:3306 - env: - MYSQL_DATABASE: 'ragnarok' - MYSQL_USER: 'ragnarok' - MYSQL_PASSWORD: 'ragnarok' - MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' - options: >- - --health-cmd="healthcheck.sh --connect --innodb_initialized" - --health-interval=5s - --health-timeout=2s - --health-retries=3 - env: - INSTALL_PACKAGES: ${{ matrix.CC }} mariadb-client libmariadbclient-dev-compat - SQLHOST: mariadb - CC: ${{ matrix.CC }} - CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} --enable-epoll CPPFLAGS=${{ matrix.CLASSIC_AUTOSPELL_LIST }} - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - - name: info - run: | - uname -a - - - name: install packages - run: | - ./tools/ci/retry.sh apt-get update - ./tools/ci/retry.sh apt-get install -y -qq $INSTALL_PACKAGES $DEBIAN_COMMON_PACKAGES - - - name: init database - run: | - ./tools/ci/travis.sh importdb ragnarok ragnarok ragnarok $SQLHOST - - - name: get plugins - run: | - ./tools/ci/travis.sh getplugins || true - - - name: build - run: | - ./tools/ci/travis.sh build $CONFIGURE_FLAGS - - # for run default config will show warnings diff --git a/.github/workflows/gccsnapshot_test.yml b/.github/workflows/gccsnapshot_test.yml index a35573e242b..29876561456 100644 --- a/.github/workflows/gccsnapshot_test.yml +++ b/.github/workflows/gccsnapshot_test.yml @@ -12,7 +12,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: [gcc] @@ -62,7 +62,7 @@ jobs: CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} --enable-lto CPPFLAGS=${{ matrix.CLASSIC_AUTOSPELL_LIST }} PACKET_VERSION: ${{ matrix.PACKET_VERSION }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/hwsapibot.yml b/.github/workflows/hwsapibot.yml index 6b39d8c405b..38311d29760 100644 --- a/.github/workflows/hwsapibot.yml +++ b/.github/workflows/hwsapibot.yml @@ -15,7 +15,7 @@ jobs: group: hwsapibot cancel-in-progress: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: info run: | diff --git a/.github/workflows/macos_latest.yml b/.github/workflows/macos_latest.yml index 005b731ad44..65a3c2f3700 100644 --- a/.github/workflows/macos_latest.yml +++ b/.github/workflows/macos_latest.yml @@ -7,13 +7,13 @@ env: MYSQL_USER: 'ragnarok' MYSQL_PASSWORD: 'ragnarok' MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' - MACOS_COMMON_PACKAGES: make zlib pcre mysql mysql-client mysql-connector-c + MACOS_COMMON_PACKAGES: make zlib pcre mysql mysql-client SQLHOST: 'localhost' jobs: build: runs-on: macos-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: [clang] diff --git a/.github/workflows/macos_m1.yml b/.github/workflows/macos_m1.yml index ae57bbc05ac..7510f791e27 100644 --- a/.github/workflows/macos_m1.yml +++ b/.github/workflows/macos_m1.yml @@ -7,13 +7,13 @@ env: MYSQL_USER: 'ragnarok' MYSQL_PASSWORD: 'ragnarok' MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' - MACOS_COMMON_PACKAGES: make zlib pcre mysql mysql-client mysql-connector-c + MACOS_COMMON_PACKAGES: make zlib pcre mysql mysql-client SQLHOST: 'localhost' jobs: build: runs-on: macos-14 - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: [clang] diff --git a/.github/workflows/mariadb.yml b/.github/workflows/mariadb.yml index b16e1312f92..14e8ce739d1 100644 --- a/.github/workflows/mariadb.yml +++ b/.github/workflows/mariadb.yml @@ -12,7 +12,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: [gcc] @@ -53,7 +53,7 @@ jobs: CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} PACKET_VERSION: ${{ matrix.PACKET_VERSION }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml index 2136cbec31d..3342cf35361 100644 --- a/.github/workflows/mysql.yml +++ b/.github/workflows/mysql.yml @@ -12,7 +12,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: [gcc] @@ -49,7 +49,7 @@ jobs: CONFIGURE_FLAGS: CC=${{ matrix.CC }} --enable-debug --enable-Werror --enable-buildbot ${{ matrix.RENEWAL }} ${{ matrix.HTTPLIB }} ${{ matrix.CLIENT_TYPE }} ${{ matrix.SANITIZER }} ${{ matrix.PACKET_VERSION }} PACKET_VERSION: ${{ matrix.PACKET_VERSION }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index e883e1afe04..def194f4e07 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -22,7 +22,7 @@ jobs: container: image: debian:unstable steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 7669990bf90..391cf307217 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -11,7 +11,7 @@ env: jobs: build: runs-on: windows-latest - timeout-minutes: 60 + timeout-minutes: 30 strategy: matrix: CC: [msbuild] diff --git a/AUTHORS b/AUTHORS index 6091cd9f5d4..8282be548f4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -80,6 +80,7 @@ jmanfffreak joel Jônatas Andreta Jose Luis Rivera Flores +jsn j-tkay KeiKun Kenpachi diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cad1e8fe7e..d46480ac5b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -792,6 +792,45 @@ All these changes only affect Renewal. Pre-renewal is unchanged. - The `is_quest` argument to `pc->gainexp()` has been changed to a `flags` bitmask enum, in order to allow expansion to different flags. (#3279) +## [v2024.08] `August 2024` + +### Added + +### Changed + +- Converted packets `CHARLOGIN_ONLINE_ACCOUNTS`, `MAPCHAR_AUTH_REQ`, `CHARLOGIN_SET_ACCOUNT_ONLINE` to the struct format. (#3304, #3312, #3314) +- Excluded the standalone (i.e. autotrader) characters from those sent to the API server. (#3314, issue #3306) +- Changed the `getpartymember()` script command to avoid the use of global temporary variables. (#3305, #3307, #3308, #3315) + - The caller now specifies an array that will be filled with the requested data. + - The amount of filled entries will be returned as the command's return value. The caller should only read up to that amount of entries from the array, as it may contain previous leftover values past that point. + - Added constants for specifying the requested data: `PT_MEMBER_NAME`, `PT_MEMBER_CHARID`, `PT_MEMBER_ACCID`. + - See the script_commands documentation for further details. + - The included scripts have been updated with the new syntax. +- Changed the `getguildmember()` script command to avoid the use of global temporary variables. (#3310, #3311, #3318) + - The caller now specifies an array that will be filled with the requested data. + - The amount of filled entries will be returned as the command's return value. The caller should only read up to that amount of entries from the array, as it may contain previous leftover values past that point. + - Added constants for specifying the requested data: `GD_MEMBER_NAME`, `GD_MEMBER_CHARID`, `GD_MEMBER_ACCID`. + - See the script_commands documentation for further details. +- Reduced timeout for the GitHub Actions CI builds to 30 minutes, to prevent stuck jobs from stalling the entire pipeline for too many hours. (#3317) + +### Fixed + +- Fixed a packet reading error causing the list of online characters on char and login server to desynchronize and invalidate the API server tokens. (#3304) +- Fixed CI builds failing due to the MariaDB client attempting to connect to the server with SSL. (#3313) +- Fixed the hwsapi commits failing because of an expired GPG key. +- Fixed HPMDataCheck containing incomplete data because of a missing include in the headers that use the `DEFINE_PACKET_ID` macro. (#3314) +- Updated the mapcache entry for `iz_ac02` (renewal-only content) to a 2012 version compatible with the included scripts. (#3316, issue #2809) +- Fixed deprecation warnings in the GitHub Actions CI builds caused by the use of unsupported nodejs v16 actions. The actions have been upgraded to their nodejs v20 versions as recommended by GitHub. (#3317) +- Fixed a deprecation warning in the GitHub Actions macOS CI builds due to a packet that was renamed. (#3317) + +### Deprecated + +- Deprecated building on GCC versions older than 7. This has been the case for at least 4 months according to the Supported Platforms rules, but this is the official deprecation warning. Support macros and workarounds will be dropped from the code at some point in the future. (#3317) + +### Removed + +- Removed GitHub Actions workflows that don't support nodejs v20. This includes the test builds for gcc-4.8, gcc-5 and gcc-6, which have been unsupported by Hercules for at least 4 months. (#3317) + ## [v2024.06] `June 2024` ### Added @@ -3891,6 +3930,7 @@ Note: everything included in this release is part of PR #3198 which consists of - New versioning scheme and project changelogs/release notes (#1853) [Unreleased]: https://github.com/HerculesWS/Hercules/compare/stable...master +[v2024.08]: https://github.com/HerculesWS/Hercules/compare/v2024.06...v2024.08 [v2024.06]: https://github.com/HerculesWS/Hercules/compare/v2024.05...v2024.06 [v2024.05]: https://github.com/HerculesWS/Hercules/compare/v2024.04...v2024.05 [v2024.04]: https://github.com/HerculesWS/Hercules/compare/v2024.03...v2024.04 diff --git a/doc/constants_pre-re.md b/doc/constants_pre-re.md index cc731dbb8ec..25ab8f2ae30 100644 --- a/doc/constants_pre-re.md +++ b/doc/constants_pre-re.md @@ -4880,7 +4880,7 @@ ### Server defines - `PACKETVER`: 20190530 -- `HERCULES_VERSION`: 202406000 +- `HERCULES_VERSION`: 202408000 - `MAX_LEVEL`: 175 - `MAX_STORAGE`: 600 - `MAX_GUILD_STORAGE`: 500 @@ -5027,6 +5027,13 @@ - `MAX_ITEM_OPTIONS`: 5 +### Navigation mode constants, use with *mesnavigation* + +- `NAV_MODE_ALL`: 0 +- `NAV_MODE_MAP`: 1 +- `NAV_MODE_NPC`: 2 +- `NAV_MODE_MOB`: 3 + ### Navigation constants, use with *navigateto* - `NAV_NONE`: 0 @@ -5037,6 +5044,7 @@ - `NAV_KAFRA_AND_AIRSHIP`: 101 - `NAV_KAFRA_AND_SCROLL`: 110 - `NAV_ALL`: 111 +- `NAV_WINDOW_SEARCH`: -222 ### BL types @@ -5562,6 +5570,18 @@ - `SIEGE_TYPE_SE`: 1 - `SIEGE_TYPE_TE`: 2 +### guildmember types + +- `GD_MEMBER_NAME`: 0 +- `GD_MEMBER_CHARID`: 1 +- `GD_MEMBER_ACCID`: 2 + +### partymember types + +- `PT_MEMBER_NAME`: 0 +- `PT_MEMBER_CHARID`: 1 +- `PT_MEMBER_ACCID`: 2 + ### guildinfo types - `GUILDINFO_NAME`: 0 diff --git a/doc/constants_re.md b/doc/constants_re.md index 066e17d10ad..40dc94ff76c 100644 --- a/doc/constants_re.md +++ b/doc/constants_re.md @@ -4878,7 +4878,7 @@ ### Server defines - `PACKETVER`: 20190530 -- `HERCULES_VERSION`: 202406000 +- `HERCULES_VERSION`: 202408000 - `MAX_LEVEL`: 175 - `MAX_STORAGE`: 600 - `MAX_GUILD_STORAGE`: 500 @@ -5025,6 +5025,13 @@ - `MAX_ITEM_OPTIONS`: 5 +### Navigation mode constants, use with *mesnavigation* + +- `NAV_MODE_ALL`: 0 +- `NAV_MODE_MAP`: 1 +- `NAV_MODE_NPC`: 2 +- `NAV_MODE_MOB`: 3 + ### Navigation constants, use with *navigateto* - `NAV_NONE`: 0 @@ -5035,6 +5042,7 @@ - `NAV_KAFRA_AND_AIRSHIP`: 101 - `NAV_KAFRA_AND_SCROLL`: 110 - `NAV_ALL`: 111 +- `NAV_WINDOW_SEARCH`: -222 ### BL types @@ -5560,6 +5568,18 @@ - `SIEGE_TYPE_SE`: 1 - `SIEGE_TYPE_TE`: 2 +### guildmember types + +- `GD_MEMBER_NAME`: 0 +- `GD_MEMBER_CHARID`: 1 +- `GD_MEMBER_ACCID`: 2 + +### partymember types + +- `PT_MEMBER_NAME`: 0 +- `PT_MEMBER_CHARID`: 1 +- `PT_MEMBER_ACCID`: 2 + ### guildinfo types - `GUILDINFO_NAME`: 0 diff --git a/doc/script_commands.txt b/doc/script_commands.txt index c0b5b58b586..1c4bb8aa3ab 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -3000,56 +3000,25 @@ Lets say the ID of a party was saved as a global variable: --------------------------------------- -*getpartymember({, }) +*getpartymember(, , ) -This command will find all members of a specified party and returns their -names (or character id or account id depending on the value of "type") -into an array of temporary global variables. There's actually quite a few -commands like this which will fill a special variable with data upon -execution and not do anything else. +This command will find all members of a specified , copy their +names (or character id or account id) depending on the into +and returns the number of party members that were found. -Upon executing this, - -$@partymembername$[] is a global temporary string array which contains all - the names of these party members. - (only set when type is 0 or not specified) - -$@partymembercid[] is a global temporary number array which contains the - character id of these party members. - (only set when type is 1) - -$@partymemberaid[] is a global temporary number array which contains the - account id of these party members. - (only set when type is 2) - -$@partymembercount is the number of party members that were found. +Valid are: -The party members will (apparently) be found regardless of whether they -are online or offline. Note that the names come in no particular order. + PT_MEMBER_NAME - Party member names + PT_MEMBER_CHARID - Party member character ID + PT_MEMBER_ACCID - Party member account ID -Be sure to use $@partymembercount to go through this array, and not -'getarraysize', because it is not cleared between runs of 'getpartymember'. -If someone with 7 party members invokes this script, the array would have -7 elements. But if another person calls up the NPC, and he has a party of -5, the server will not clear the array for you, overwriting the values -instead. So in addition to returning the 5 member names, the 6th and 7th -elements from the last call remain, and you will get 5+2 members, of which -the last 2 don't belong to the new guy's party. $@partymembercount will -always contain the correct number, (5) unlike 'getarraysize()' which will -return 7 in this case. +Make sure to use string variable for PT_MEMBER_NAME and +int variable for PT_MEMBER_CHARID and PT_MEMBER_ACCID -Example 1: list party member names +Example 1: Listing party member names // get the party member names - getpartymember(getcharid(CHAR_ID_PARTY), 0); - - // It's a good idea to copy the global temporary $@partymember***** - // variables to your own scope variables because if you have pauses in - // this script (sleep, sleep2, next, close2, input, menu, select, or - // prompt), another player could click this NPC, trigger - // 'getpartymember', and overwrite the $@partymember***** variables. - .@count = $@partymembercount; - copyarray(.@name$[0], $@partymembername$[0], $@partymembercount); + .@count = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_NAME, .@name$); // list the party member names for (.@i = 0; .@i < .@count; ++.@i) { @@ -3057,61 +3026,19 @@ Example 1: list party member names } close(); - -Example 2: check party count (with a next() pause), before warping to event - - .register_num = 5; // How many party members are required? +Example 2: Get online count // get the charID and accountID of character's party members - getpartymember(getcharid(CHAR_ID_PARTY), 1); - getpartymember(getcharid(CHAR_ID_PARTY), 2); - - if ($@partymembercount != .register_num) { - mes("Please form a party of "+ .register_num +" to continue"); - close(); - } + // we only need to count the member once so we assign that + // to the our second command call + getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_CHARID, .@charid); + .@count = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@accid); - // loop through both and use 'isloggedin' to count online party members - for (.@i = 0; .@i < $@partymembercount; ++.@i) - if (isloggedin($@partymemberaid[.@i], $@partymembercid[.@i])) + for (.@i = 0; .@i < .@count; ++.@i) { + if (isloggedin(.@accid[.@i], .@charid[.@i])) .@count_online++; - // We search accountID & charID because a single party can have - // multiple characters from the same account. Without searching - // through the charID, if a player has 2 characters from the same - // account inside the party but only 1 char online, it would count - // their online char twice. - - if (.@count_online != .register_num) { - mes("All your party members must be online to continue"); - close(); - } - - // copy the array to prevent players cheating the system - copyarray(.@partymembercid, $@partymembercid, .register_num); - - mes("Are you ready?"); - next(); // careful here - select("Yes"); - - // When a script hits a next, menu, sleep or input that pauses the - // script, players can invite or /leave and make changes in their - // party. To prevent this, we call getpartymember again and compare - // with the original values. - - getpartymember(getcharid(CHAR_ID_PARTY), 1); - if ($@partymembercount != .register_num) { - mes("You've made changes to your party !"); - close(); - } - for (.@i = 0; .@i < $@partymembercount; ++.@i) { - if (.@partymembercid[.@i] != $@partymembercid[.@i]) { - mes("You've made changes to your party !"); - close(); - } } - - // Finally, it's safe to start the event! - warpparty("event_map", 0, 0, getcharid(CHAR_ID_PARTY), true); + end; --------------------------------------- @@ -4220,33 +4147,23 @@ Example: --------------------------------------- -*getguildmember({, }); +*getguildmember(, , ); -This command will find all members of a specified guild and returns their names -(or character id or account id depending on the value of "type") into an array -of temporary global variables. - -Upon executing this, +This command will find all members of a specified , copy their +names (or character id or account id) depending on the into +and returns the number of guild members that were found. -$@guildmembername$[] is a global temporary string array which contains all the - names of these guild members. - (only set when type is 0 or not specified) - -$@guildmembercid[] is a global temporary number array which contains the - character id of these guild members. - (only set when type is 1) - -$@guildmemberaid[] is a global temporary number array which contains the - account id of these guild members. - (only set when type is 2) +Valid are: -$@guildmembercount is the number of guild members that were found. + GD_MEMBER_NAME - Guild member names + GD_MEMBER_CHARID - Guild member character ID + GD_MEMBER_ACCID - Guild member account ID The guild members will be found regardless of whether they are online or offline. -Note that the names come in no particular order. +Note that the results come in no particular order. -Be sure to use $@guildmembercount to go through this array, and not -getarraysize(), because it is not cleared between runs of getguildmember(). +Make sure to use string variable for GD_MEMBER_NAME and +int variable for GD_MEMBER_CHARID and GD_MEMBER_ACCID For usage examples, see getpartymember(). diff --git a/maps/re/iz_ac02.mcache b/maps/re/iz_ac02.mcache index c939a1315f5..c62875fb47f 100644 Binary files a/maps/re/iz_ac02.mcache and b/maps/re/iz_ac02.mcache differ diff --git a/maps/re/iz_ac02_a.mcache b/maps/re/iz_ac02_a.mcache index c939a1315f5..c62875fb47f 100644 Binary files a/maps/re/iz_ac02_a.mcache and b/maps/re/iz_ac02_a.mcache differ diff --git a/maps/re/iz_ac02_b.mcache b/maps/re/iz_ac02_b.mcache index c939a1315f5..c62875fb47f 100644 Binary files a/maps/re/iz_ac02_b.mcache and b/maps/re/iz_ac02_b.mcache differ diff --git a/maps/re/iz_ac02_c.mcache b/maps/re/iz_ac02_c.mcache index c939a1315f5..c62875fb47f 100644 Binary files a/maps/re/iz_ac02_c.mcache and b/maps/re/iz_ac02_c.mcache differ diff --git a/maps/re/iz_ac02_d.mcache b/maps/re/iz_ac02_d.mcache index c939a1315f5..c62875fb47f 100644 Binary files a/maps/re/iz_ac02_d.mcache and b/maps/re/iz_ac02_d.mcache differ diff --git a/npc/custom/quests/hunting_missions.txt b/npc/custom/quests/hunting_missions.txt index 4bd42436dbc..40c0aa3ccd1 100644 --- a/npc/custom/quests/hunting_missions.txt +++ b/npc/custom/quests/hunting_missions.txt @@ -275,11 +275,11 @@ OnNPCKillEvent: } else if (.Party) { set .@mob, killedrid; getmapxy(.@map1$, .@x1, .@y1, UNITTYPE_PC); - getpartymember getcharid(CHAR_ID_PARTY),1; - getpartymember getcharid(CHAR_ID_PARTY),2; - for(set .@i,0; .@i<$@partymembercount; set .@i,.@i+1) { - if (isloggedin($@partymemberaid[.@i], $@partymembercid[.@i])) { - attachrid $@partymemberaid[.@i]; + getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@accid); + .@count = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_CHARID, .@charid); + for (.@i = 0; .@i < .@count; .@i++) { + if (isloggedin(.@accid[.@i], .@charid[.@i])) { + attachrid(.@accid[.@i]); if (#Mission_Count && Mission0 && Hp > 0) { getmapxy(.@map2$, .@x2, .@y2, UNITTYPE_PC); if ((.@map1$ == .@map2$ || .Party == 1) && (distance(.@x1,.@y1,.@x2,.@y2) <= 30 || .Party < 3)) { diff --git a/npc/other/marriage.txt b/npc/other/marriage.txt index 546ebe48ae5..49e5ddb6497 100644 --- a/npc/other/marriage.txt +++ b/npc/other/marriage.txt @@ -577,8 +577,7 @@ prt_church,100,128,4 script Bishop#w 1_M_PASTOR,{ if (!getpartnerid()) { if (!$@wedding) { if (wedding_sign == 1) { - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); if (.@partymembercount == 2) { if (Sex == SEX_MALE) { $@wedding = 1; @@ -648,8 +647,7 @@ prt_church,100,128,4 script Bishop#w 1_M_PASTOR,{ } else if ($@wedding == 1) { if (wedding_sign == 1) { - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); if (.@partymembercount == 2) { if (Sex == SEX_FEMALE) { if (strcharinfo(PC_NAME) == $@wed_bride$) { diff --git a/npc/quests/guildrelay.txt b/npc/quests/guildrelay.txt index 2d7aeceaf54..fbfa3ebde05 100644 --- a/npc/quests/guildrelay.txt +++ b/npc/quests/guildrelay.txt @@ -2527,8 +2527,7 @@ close; } } - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); .@partyleader = getpartyleader(getcharid(CHAR_ID_PARTY),2); if (guildrelay_q == 91) { if (.@partymembercount == 6) { diff --git a/npc/quests/partyrelay.txt b/npc/quests/partyrelay.txt index 19f78a84fb3..3a7e55f8d8a 100644 --- a/npc/quests/partyrelay.txt +++ b/npc/quests/partyrelay.txt @@ -34,8 +34,7 @@ //========================================================================= payon,103,113,3 script Ledrion#payon::RelayLedrion 4_M_MANAGER,{ - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); .@partyleader = getpartyleader(getcharid(CHAR_ID_PARTY),2); if (checkweight(Resin,300) == 0) { mes "^3355FFWait a minute! You're"; @@ -402,8 +401,7 @@ payon,103,113,3 script Ledrion#payon::RelayLedrion 4_M_MANAGER,{ } payon,83,327,3 script Gatan#payon::RelayGatan 4_M_04,{ - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); .@partyleader = getpartyleader(getcharid(CHAR_ID_PARTY),2); if (checkweight(Resin,300) == 0) { mes "^3355FFWait a minute! You're"; @@ -1837,8 +1835,7 @@ payon,83,327,3 script Gatan#payon::RelayGatan 4_M_04,{ } payon,204,221,3 script Bafhail#payon::RelayBafhail 4_M_JOB_BLACKSMITH,{ - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); .@partyleader = getpartyleader(getcharid(CHAR_ID_PARTY),2); if (checkweight(Resin,300) == 0) { mes "^3355FFWait a minute! You're"; @@ -2470,8 +2467,7 @@ payon,204,221,3 script Bafhail#payon::RelayBafhail 4_M_JOB_BLACKSMITH,{ } payon,168,314,3 script Lospii#payon::RelayLospii 4_M_KID1,{ - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); .@partyleader = getpartyleader(getcharid(CHAR_ID_PARTY),2); if (checkweight(Resin,300) == 0) { mes "^3355FFWait a minute! You're"; diff --git a/npc/quests/quests_louyang.txt b/npc/quests/quests_louyang.txt index a1a52986b99..b6232624d3c 100644 --- a/npc/quests/quests_louyang.txt +++ b/npc/quests/quests_louyang.txt @@ -4643,8 +4643,7 @@ lou_in02,77,37,7 script Hermit 4_M_CHNOLD,{ mes strcharinfo(PC_NAME)+ "...!"; mes "Your name is now engraved on this bloody pledge board. We will fight together to the death for Louyang's future!"; next; - getpartymember(getcharid(CHAR_ID_PARTY)); - @partymember = $@partymembercount; + @partymember = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); if (getpartyleader(getcharid(CHAR_ID_PARTY),1) == getcharid(CHAR_ID_CHAR) || !@partymember) { mes "[Sun Mao]"; mes "Now, the most important thing for our cause is to gather more recruits and increase our numbers. Please find others who will join us in our fight."; @@ -4677,8 +4676,7 @@ lou_in02,77,37,7 script Hermit 4_M_CHNOLD,{ mes "Go back safe."; close; } - getpartymember(getcharid(CHAR_ID_PARTY)); - @partymember = $@partymembercount; + @partymember = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); if (QL_REVOL < 8) { if (@partymember == QL_REVOL +1) { if (@partymember != 8) { @@ -4869,8 +4867,7 @@ lou_in02,77,37,7 script Hermit 4_M_CHNOLD,{ lou_in01,43,147,3 script Gunpowder Expert 4_M_ALCHE_C,{ if (ch_make == 0) { - getpartymember(getcharid(CHAR_ID_PARTY)); - @partymember = $@partymembercount; + @partymember = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); if (!QL_REVOL) { mes "[Hao Chenryu]"; mes "Who..."; diff --git a/npc/quests/quests_morocc.txt b/npc/quests/quests_morocc.txt index cd99348d5a3..9fada618a5f 100644 --- a/npc/quests/quests_morocc.txt +++ b/npc/quests/quests_morocc.txt @@ -946,9 +946,7 @@ moc_fild20,354,183,3 script Continental Guard#01::MocConGuard 4_M_MOC_SOLDIER,3, close; case 2: if ($@re_moc < 3) { - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; - copyarray .@partymembername$[0],$@partymembername$[0],.@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_NAME, .@partymembername$); while (.@partymembercount >= 0) { .@name$ = .@partymembername$[.@partymembercount]; if (isloggedin(getcharid(CHAR_ID_ACCOUNT,.@name$))) { @@ -1009,9 +1007,7 @@ moc_fild20,354,183,3 script Continental Guard#01::MocConGuard 4_M_MOC_SOLDIER,3, mes "[Continental Guard]"; mes "Ah, you're an adventurer working for the Continental Guard. Nice to meet you. Feel free to ask me if you need my assistance."; next; - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; - copyarray .@partymembername$[0],$@partymembername$[0],.@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_NAME, .@partymembername$); while (.@partymembercount >= 0) { .@name$ = .@partymembername$[.@partymembercount]; if (isloggedin(getcharid(CHAR_ID_ACCOUNT,.@name$))) { diff --git a/npc/quests/quests_nameless.txt b/npc/quests/quests_nameless.txt index af4d5851de8..cb2b6439b06 100644 --- a/npc/quests/quests_nameless.txt +++ b/npc/quests/quests_nameless.txt @@ -10177,8 +10177,7 @@ moc_fild18,108,116,0 script #treasure CLEAR_NPC,{ mes "protection to get the treasure.^000000"; next; input(.@input$); - getpartymember(getcharid(CHAR_ID_PARTY)); - .@partymembercount = $@partymembercount; + .@partymembercount = getpartymember(getcharid(CHAR_ID_PARTY), PT_MEMBER_ACCID, .@temp); if (.@partymembercount > 1) { if ((.@input$ == "OpenSesame" && treasure_nd == 9) || (.@input$ == "UnlockTreasure" && treasure_nd == 10)) { mes "^3355FFThe Z Gang must have split"; diff --git a/npc/re/instances/MalangdoCulvert.txt b/npc/re/instances/MalangdoCulvert.txt index 271a0393a37..3e3c8d0e917 100644 --- a/npc/re/instances/MalangdoCulvert.txt +++ b/npc/re/instances/MalangdoCulvert.txt @@ -784,9 +784,8 @@ OnEnable: areamonster(.@map$, .@c[0], .@c[1], .@c[2], .@c[3], _("Abysmal Cornutus"), MD_CORNUTUS, rand(1, 3), .@label$); specialeffect(EF_MAPPILLAR2, ALL_SAMEMAP); //currently broken getmapxy(.@map$, .@x, .@y, UNITTYPE_NPC); - getpartymember('party_id, 2); - copyarray(.@partymemberaid[0], $@partymemberaid[0], $@partymembercount); - for(.@i = 0; .@i<$@partymembercount; ++.@i) { + .@partymembercount = getpartymember('party_id, PT_MEMBER_ACCID, .@partymemberaid); + for(.@i = 0; .@i < .@partymembercount; ++.@i) { if (attachrid(.@partymemberaid[.@i])) { if (strcharinfo(PC_MAP) == .@map$) viewpoint(0, .@x, .@y, .@index, C_YELLOW); diff --git a/src/char/char.c b/src/char/char.c index 20d4574915a..6107b509e9d 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -50,6 +50,8 @@ #include "common/HPM.h" #include "common/apipackets.h" #include "common/cbasetypes.h" +#include "common/charloginpackets.h" +#include "common/mapcharpackets.h" #include "common/chunked.h" #include "common/conf.h" #include "common/console.h" @@ -203,12 +205,16 @@ static struct DBData char_create_online_char_data(union DBKey key, va_list args) return DB->ptr2data(character); } -static void char_set_account_online(int account_id) +static void char_set_account_online(int account_id, bool standalone) { - WFIFOHEAD(chr->login_fd,6); - WFIFOW(chr->login_fd,0) = 0x272b; - WFIFOL(chr->login_fd,2) = account_id; - WFIFOSET(chr->login_fd,6); + WFIFOHEAD(chr->login_fd, sizeof(struct PACKET_CHARLOGIN_SET_ACCOUNT_ONLINE)); + + struct PACKET_CHARLOGIN_SET_ACCOUNT_ONLINE *p = WFIFOP(chr->login_fd, 0); + p->packetType = HEADER_CHARLOGIN_SET_ACCOUNT_ONLINE; + p->account_id = account_id; + p->standalone = standalone ? 1 : 0; + + WFIFOSET(chr->login_fd, sizeof(*p)); } static void char_set_account_offline(int account_id) @@ -242,10 +248,10 @@ static void char_set_char_charselect(int account_id) } if (chr->login_fd > 0 && !sockt->session[chr->login_fd]->flag.eof) - chr->set_account_online(account_id); + chr->set_account_online(account_id, false); } -static void char_set_char_online(bool is_initializing, int char_id, int account_id) +static void char_set_char_online(bool is_initializing, int char_id, int account_id, bool standalone) { struct online_char_data* character; struct mmo_charstatus *cp; @@ -279,7 +285,7 @@ static void char_set_char_online(bool is_initializing, int char_id, int account_ //Notify login server if (chr->login_fd > 0 && !sockt->session[chr->login_fd]->flag.eof) - chr->set_account_online(account_id); + chr->set_account_online(account_id, standalone); } static void char_set_char_offline(int char_id, int account_id) @@ -3274,7 +3280,7 @@ static void char_parse_frommap_save_character(int fd) } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. ShowError("parse_from_map (save-char): Received data for non-existing/offline character (%d:%d).\n", aid, cid); - chr->set_char_online(false, cid, aid); + chr->set_char_online(false, cid, aid, false); } if (RFIFOB(fd,12)) { @@ -3676,7 +3682,7 @@ static void char_parse_frommap_set_all_offline(int fd) static void char_parse_frommap_set_char_online(int fd) { - chr->set_char_online(false, RFIFOL(fd, 2), RFIFOL(fd, 6)); + chr->set_char_online(false, RFIFOL(fd, 2), RFIFOL(fd, 6), false); RFIFOSKIP(fd,10); } @@ -3780,13 +3786,16 @@ static void char_parse_frommap_auth_request(int fd) struct char_auth_node* node; struct mmo_charstatus* cd; - int account_id = RFIFOL(fd,2); - int char_id = RFIFOL(fd,6); - int login_id1 = RFIFOL(fd,10); - char sex = RFIFOB(fd,14); - uint32 ip = ntohl(RFIFOL(fd,15)); - char standalone = RFIFOB(fd, 19); - RFIFOSKIP(fd,20); + const struct PACKET_MAPCHAR_AUTH_REQ *p = RFIFOP(fd, 0); + + int account_id = p->account_id; + int char_id = p->char_id; + int login_id1 = p->login_id1; + char sex = p->sex; + uint32 ip = ntohl(p->client_addr); + uint8 standalone = p->standalone; + + RFIFOSKIP(fd, sizeof(struct PACKET_MAPCHAR_AUTH_REQ)); node = (struct char_auth_node*)idb_get(auth_db, account_id); cd = (struct mmo_charstatus*)uidb_get(chr->char_db_,char_id); @@ -3796,11 +3805,11 @@ static void char_parse_frommap_auth_request(int fd) cd = (struct mmo_charstatus*)uidb_get(chr->char_db_,char_id); } - if( core->runflag == CHARSERVER_ST_RUNNING && cd && standalone ) { + if (core->runflag == CHARSERVER_ST_RUNNING && cd != NULL && standalone != 0) { cd->sex = sex; chr->map_auth_ok(fd, account_id, NULL, cd); - chr->set_char_online(false, char_id, account_id); + chr->set_char_online(false, char_id, account_id, true); return; } @@ -3819,7 +3828,7 @@ static void char_parse_frommap_auth_request(int fd) chr->map_auth_ok(fd, account_id, node, cd); // only use the auth once and mark user online idb_remove(auth_db, account_id); - chr->set_char_online(false, char_id, account_id); + chr->set_char_online(false, char_id, account_id, (standalone != 0)); } else {// auth failed @@ -4039,8 +4048,8 @@ static int char_parse_frommap(int fd) chr->parse_frommap_ping(fd); break; - case 0x2b26: // auth request from map-server - if (RFIFOREST(fd) < 20) + case HEADER_MAPCHAR_AUTH_REQ: // auth request from map-server + if (RFIFOREST(fd) < sizeof(struct PACKET_MAPCHAR_AUTH_REQ)) return 0; { @@ -4575,7 +4584,7 @@ static void char_parse_char_select(int fd, struct char_session_data *sd, uint32 } /* set char as online prior to loading its data so 3rd party applications will realize the sql data is not reliable */ - chr->set_char_online(true, char_id, sd->account_id); + chr->set_char_online(true, char_id, sd->account_id, false); loginif->set_char_online(char_id, sd->account_id); if (!chr->mmo_char_fromsql(char_id, &char_dat, true)) { /* failed? set it back offline */ chr->set_char_offline(char_id, sd->account_id); @@ -5298,10 +5307,11 @@ static int char_send_accounts_tologin_sub(union DBKey key, struct DBData *data, { struct online_char_data* character = DB->data2ptr(data); int* i = va_arg(ap, int*); + int* accounts = va_arg(ap, int *); nullpo_ret(character); if (character->mapserver_connection == OCS_CONNECTED) { - WFIFOL(chr->login_fd,8+(*i)*4) = character->account_id; + accounts[*i] = character->account_id; (*i)++; return 1; } @@ -5310,18 +5320,24 @@ static int char_send_accounts_tologin_sub(union DBKey key, struct DBData *data, static int char_send_accounts_tologin(int tid, int64 tick, int id, intptr_t data) { - if (chr->login_fd > 0 && sockt->session[chr->login_fd]) - { + if (chr->login_fd > 0 && sockt->session[chr->login_fd] != NULL) { // send account list to login server int users = chr->online_char_db->size(chr->online_char_db); int i = 0; - WFIFOHEAD(chr->login_fd,8+users*4); - WFIFOW(chr->login_fd,0) = 0x272d; - chr->online_char_db->foreach(chr->online_char_db, chr->send_accounts_tologin_sub, &i, users); - WFIFOW(chr->login_fd,2) = 8+ i*4; - WFIFOL(chr->login_fd,4) = i; - WFIFOSET(chr->login_fd,WFIFOW(chr->login_fd,2)); + struct PACKET_CHARLOGIN_ONLINE_ACCOUNTS *p; + int len = sizeof(struct PACKET_CHARLOGIN_ONLINE_ACCOUNTS) + sizeof(*p->accounts) * users; + + WFIFOHEAD(chr->login_fd, len); + p = WFIFOP(chr->login_fd, 0); + p->packetType = HEADER_CHARLOGIN_ONLINE_ACCOUNTS; + + chr->online_char_db->foreach(chr->online_char_db, chr->send_accounts_tologin_sub, &i, p->accounts); + + p->packetLength = sizeof(struct PACKET_CHARLOGIN_ONLINE_ACCOUNTS) + sizeof(*p->accounts) * i; + p->list_length = i; + + WFIFOSET(chr->login_fd, p->packetLength); } return 0; } diff --git a/src/char/char.h b/src/char/char.h index bb697bb609a..325b964840e 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -140,10 +140,10 @@ struct char_interface { int (*waiting_disconnect) (int tid, int64 tick, int id, intptr_t data); int (*delete_char_sql) (int char_id); struct DBData (*create_online_char_data) (union DBKey key, va_list args); - void (*set_account_online) (int account_id); + void (*set_account_online) (int account_id, bool standalone); void (*set_account_offline) (int account_id); void (*set_char_charselect) (int account_id); - void (*set_char_online) (bool is_initializing, int char_id, int account_id); + void (*set_char_online) (bool is_initializing, int char_id, int account_id, bool standalone); void (*set_char_offline) (int char_id, int account_id); int (*db_setoffline) (union DBKey key, struct DBData *data, va_list ap); int (*db_kickoffline) (union DBKey key, struct DBData *data, va_list ap); diff --git a/src/char/packets_hc_struct.h b/src/char/packets_hc_struct.h index 08ae5b83ffb..3a4fe27c3f4 100644 --- a/src/char/packets_hc_struct.h +++ b/src/char/packets_hc_struct.h @@ -23,6 +23,7 @@ #include "common/hercules.h" #include "common/mmo.h" #include "common/packetsstatic_len.h" +#include "common/packetsmacro.h" /* Packets Structs */ #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h index a8d6f53aca3..5d4bd1fdf25 100644 --- a/src/common/HPMDataCheck.h +++ b/src/common/HPMDataCheck.h @@ -254,10 +254,18 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { #else #define COMMON_BASE62_H #endif // COMMON_BASE62_H + #ifdef COMMON_CHARLOGINPACKETS_H + { "PACKET_CHARLOGIN_ONLINE_ACCOUNTS", sizeof(struct PACKET_CHARLOGIN_ONLINE_ACCOUNTS), SERVER_TYPE_ALL }, + { "PACKET_CHARLOGIN_SET_ACCOUNT_ONLINE", sizeof(struct PACKET_CHARLOGIN_SET_ACCOUNT_ONLINE), SERVER_TYPE_ALL }, + #else + #define COMMON_CHARLOGINPACKETS_H + #endif // COMMON_CHARLOGINPACKETS_H #ifdef COMMON_CHARMAPPACKETS_H { "PACKET_CHARMAP_AGENCY_JOIN_PARTY", sizeof(struct PACKET_CHARMAP_AGENCY_JOIN_PARTY), SERVER_TYPE_ALL }, { "PACKET_CHARMAP_GUILD_EMBLEM", sizeof(struct PACKET_CHARMAP_GUILD_EMBLEM), SERVER_TYPE_ALL }, { "PACKET_CHARMAP_GUILD_INFO", sizeof(struct PACKET_CHARMAP_GUILD_INFO), SERVER_TYPE_ALL }, + { "PACKET_CHARMAP_GUILD_INFO_EMBLEM", sizeof(struct PACKET_CHARMAP_GUILD_INFO_EMBLEM), SERVER_TYPE_ALL }, + { "PACKET_CHARMAP_GUILD_INFO_EMPTY", sizeof(struct PACKET_CHARMAP_GUILD_INFO_EMPTY), SERVER_TYPE_ALL }, #else #define COMMON_CHARMAPPACKETS_H #endif // COMMON_CHARMAPPACKETS_H @@ -322,6 +330,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { #endif // COMMON_HPMI_H #ifdef COMMON_MAPCHARPACKETS_H { "PACKET_MAPCHAR_AGENCY_JOIN_PARTY_REQ", sizeof(struct PACKET_MAPCHAR_AGENCY_JOIN_PARTY_REQ), SERVER_TYPE_ALL }, + { "PACKET_MAPCHAR_AUTH_REQ", sizeof(struct PACKET_MAPCHAR_AUTH_REQ), SERVER_TYPE_ALL }, { "PACKET_MAPCHAR_GUILD_EMBLEM", sizeof(struct PACKET_MAPCHAR_GUILD_EMBLEM), SERVER_TYPE_ALL }, #else #define COMMON_MAPCHARPACKETS_H diff --git a/src/common/Makefile.in b/src/common/Makefile.in index ed7baebcfa1..136fe456e53 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -62,7 +62,7 @@ COMMON_H = atomic.h cbasetypes.h base62.h conf.h console.h core.h db.h des.h ers grfio.h hercules.h HPM.h HPMi.h memmgr.h memmgr_inc.h mapindex.h \ md5calc.h mmo.h mutex.h nullpo.h packets.h packets_len.h packets_struct.h random.h \ showmsg.h socket.h spinlock.h sql.h strlib.h sysinfo.h thread.h \ - timer.h utils.h winapi.h api.h charmappackets.h mapcharpackets.h \ + timer.h utils.h winapi.h api.h charloginpackets.h charmappackets.h mapcharpackets.h \ chunked/rfifo.h chunked/wfifo.h config/defc.h config/emblems.h config/undefc.h \ ../plugins/HPMHooking.h COMMON_PH = diff --git a/src/common/charloginpackets.h b/src/common/charloginpackets.h new file mode 100644 index 00000000000..4e22047840f --- /dev/null +++ b/src/common/charloginpackets.h @@ -0,0 +1,53 @@ +/** + * This file is part of Hercules. + * http://herc.ws - http://github.com/HerculesWS/Hercules + * + * Copyright (C) 2012-2024 Hercules Dev Team + * Copyright (C) Athena Dev Teams + * + * Hercules is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef COMMON_CHARLOGINPACKETS_H +#define COMMON_CHARLOGINPACKETS_H + +// Packets sent by Char-Server to Login-Server + +#include "common/hercules.h" +#include "common/packetsmacro.h" + +/* Packets Structs */ +#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute +#pragma pack(push, 1) +#endif // not NetBSD < 6 / Solaris + +struct PACKET_CHARLOGIN_SET_ACCOUNT_ONLINE { + int16 packetType; + int account_id; + uint8 standalone; // 0 - real player (false) / 1 - standalone/server generated (true) +} __attribute__((packed)); +DEFINE_PACKET_ID(CHARLOGIN_SET_ACCOUNT_ONLINE, 0x272b) + +struct PACKET_CHARLOGIN_ONLINE_ACCOUNTS { + int16 packetType; + uint16 packetLength; + uint32 list_length; + int accounts[]; +} __attribute__((packed)); +DEFINE_PACKET_ID(CHARLOGIN_ONLINE_ACCOUNTS, 0x272d) + +#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute +#pragma pack(pop) +#endif // not NetBSD < 6 / Solaris + +#endif /* COMMON_CHARLOGINPACKETS_H */ diff --git a/src/common/charmappackets.h b/src/common/charmappackets.h index 16b0de4650d..1166bb6d7f3 100644 --- a/src/common/charmappackets.h +++ b/src/common/charmappackets.h @@ -23,6 +23,7 @@ #define COMMON_CHARMAPPACKETS_H #include "common/hercules.h" +#include "common/packetsmacro.h" /* Packets Structs */ #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute diff --git a/src/common/mapcharpackets.h b/src/common/mapcharpackets.h index 4f4b5ac5512..fe997208ecd 100644 --- a/src/common/mapcharpackets.h +++ b/src/common/mapcharpackets.h @@ -23,12 +23,24 @@ #define COMMON_MAPCHARPACKETS_H #include "common/hercules.h" +#include "common/packetsmacro.h" /* Packets Structs */ #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #pragma pack(push, 1) #endif // not NetBSD < 6 / Solaris +struct PACKET_MAPCHAR_AUTH_REQ { + int16 packetType; + int account_id; + int char_id; + int login_id1; + uint8 sex; + int client_addr; + uint8 standalone; // 0 - real player (false) / 1 - standalone/server generated (true) +} __attribute__((packed)); +DEFINE_PACKET_ID(MAPCHAR_AUTH_REQ, 0x2b26) + struct PACKET_MAPCHAR_AGENCY_JOIN_PARTY_REQ { int16 packetType; int char_id; diff --git a/src/config/core.h b/src/config/core.h index 6faa3ea1faf..657f29bbe65 100644 --- a/src/config/core.h +++ b/src/config/core.h @@ -22,7 +22,7 @@ #define CONFIG_CORE_H /// Hercules version. From tag vYYYY.MM(+PPP) -> YYYYMMPPP -#define HERCULES_VERSION 202406000 +#define HERCULES_VERSION 202408000 /// Max number of items on @autolootid list #define AUTOLOOTITEM_SIZE 10 diff --git a/src/login/login.c b/src/login/login.c index 8a4458bd857..206d01b07ac 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -32,6 +32,7 @@ #include "common/HPM.h" #include "common/apipackets.h" #include "common/cbasetypes.h" +#include "common/charloginpackets.h" #include "common/conf.h" #include "common/core.h" #include "common/db.h" @@ -662,9 +663,16 @@ static void login_fromchar_parse_unban(int fd, int id, const char *const ip) static void login_fromchar_parse_account_online(int fd, int id) { - login->add_online_user(id, RFIFOL(fd,2)); - lapiif->connect_user_char(id, RFIFOL(fd, 2)); - RFIFOSKIP(fd, 6); + const struct PACKET_CHARLOGIN_SET_ACCOUNT_ONLINE *p = RFIFOP(fd, 0); + + login->add_online_user(id, p->account_id); + + // "standalone" players (such as autotraders) does not exists in API server, so we should not send data about them + // or we will get errors from API server + if (p->standalone == 0) + lapiif->connect_user_char(id, p->account_id); + + RFIFOSKIP(fd, sizeof(*p)); } static void login_fromchar_parse_account_offline(int fd) @@ -675,17 +683,17 @@ static void login_fromchar_parse_account_offline(int fd) static void login_fromchar_parse_online_accounts(int fd, int id) { - uint32 i, users; login->online_db->foreach(login->online_db, login->online_db_setoffline, id); //Set all chars from this char-server offline first - users = RFIFOW(fd,4); - for (i = 0; i < users; i++) { - int aid = RFIFOL(fd,6+i*4); - struct online_login_data *p = idb_ensure(login->online_db, aid, login->create_online_user); - p->char_server = id; - if (p->waiting_disconnect != INVALID_TIMER) - { - timer->delete(p->waiting_disconnect, login->waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; + + const struct PACKET_CHARLOGIN_ONLINE_ACCOUNTS *p = RFIFOP(fd, 0); + for (uint32 i = 0; i < p->list_length; i++) { + int aid = p->accounts[i]; + struct online_login_data *login_data = idb_ensure(login->online_db, aid, login->create_online_user); + login_data->char_server = id; + + if (login_data->waiting_disconnect != INVALID_TIMER) { + timer->delete(login_data->waiting_disconnect, login->waiting_disconnect_timer); + login_data->waiting_disconnect = INVALID_TIMER; } } } @@ -938,8 +946,8 @@ static int login_parse_fromchar(int fd) } break; - case 0x272b: // Set account_id to online [Wizputer] - if( RFIFOREST(fd) < 6 ) + case HEADER_CHARLOGIN_SET_ACCOUNT_ONLINE: // Set account_id to online [Wizputer] + if (RFIFOREST(fd) < sizeof(struct PACKET_CHARLOGIN_SET_ACCOUNT_ONLINE)) return 0; login->fromchar_parse_account_online(fd, id); break; @@ -950,7 +958,7 @@ static int login_parse_fromchar(int fd) login->fromchar_parse_account_offline(fd); break; - case 0x272d: // Receive list of all online accounts. [Skotlex] + case HEADER_CHARLOGIN_ONLINE_ACCOUNTS: // Receive list of all online accounts. [Skotlex] if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) return 0; { diff --git a/src/map/chrif.c b/src/map/chrif.c index caebf6981fb..d0f576b61f1 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -42,6 +42,7 @@ #include "common/HPM.h" #include "common/cbasetypes.h" #include "common/ers.h" +#include "common/mapcharpackets.h" #include "common/memmgr.h" #include "common/msgtable.h" #include "common/nullpo.h" @@ -470,15 +471,17 @@ static void chrif_authreq(struct map_session_data *sd, bool hstandalone) return; } - WFIFOHEAD(chrif->fd,20); - WFIFOW(chrif->fd,0) = 0x2b26; - WFIFOL(chrif->fd,2) = sd->status.account_id; - WFIFOL(chrif->fd,6) = sd->status.char_id; - WFIFOL(chrif->fd,10) = sd->login_id1; - WFIFOB(chrif->fd,14) = sd->status.sex; - WFIFOL(chrif->fd,15) = htonl(sockt->session[sd->fd]->client_addr); - WFIFOB(chrif->fd,19) = hstandalone ? 1 : 0; - WFIFOSET(chrif->fd,20); + WFIFOHEAD(chrif->fd, sizeof(struct PACKET_MAPCHAR_AUTH_REQ)); + struct PACKET_MAPCHAR_AUTH_REQ *p = WFIFOP(chrif->fd, 0); + p->packetType = HEADER_MAPCHAR_AUTH_REQ; + p->account_id = sd->status.account_id; + p->char_id = sd->status.char_id; + p->login_id1 = sd->login_id1; + p->sex = sd->status.sex; + p->client_addr = htonl(sockt->session[sd->fd]->client_addr); + p->standalone = hstandalone ? 1 : 0; + WFIFOSET(chrif->fd, sizeof(struct PACKET_MAPCHAR_AUTH_REQ)); + chrif->sd_to_auth(sd, ST_LOGIN); } diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 60761d42bb8..9df2a3c0088 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -26,6 +26,7 @@ #include "common/cbasetypes.h" #include "common/mmo.h" #include "common/packetsstatic_len.h" +#include "common/packetsmacro.h" // Packet DB #define MAX_PACKET_POS 20 diff --git a/src/map/script.c b/src/map/script.c index 108c2d008a1..0024462c2a7 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -9920,41 +9920,75 @@ static BUILDIN(getpartyname) /*========================================== * Get the information of the members of a party by type - * @party_id, @type - * return by @type : - * - : nom des membres - * 1 : char_id des membres - * 2 : account_id des membres + * getpartymember(, , ); *------------------------------------------*/ static BUILDIN(getpartymember) { - struct party_data *p; - int j=0,type=0; + struct map_session_data *sd = NULL; + struct party_data *p = party->search(script_getnum(st, 2)); + enum partymember_type type = script_getnum(st, 3); + struct script_data *data = script_getdata(st, 4); + const char *varname = reference_getname(data); + int id = reference_getid(data); + int num = 0; - p=party->search(script_getnum(st,2)); + if (!data_isreference(data) || reference_toconstant(data)) { + ShowError("buildin_getpartymember: Target argument is not a variable\n"); + script->reportdata(data); + st->state = END; + return false; + } - if (script_hasdata(st,3)) - type=script_getnum(st,3); + if (type < PT_MEMBER_NAME || type > PT_MEMBER_ACCID) { + ShowError("buildin_getpartymember: Invalid type argument\n"); + script->reportdata(data); + st->state = END; + return false; + } + + if (!is_int_variable(varname) && (type == PT_MEMBER_CHARID || type == PT_MEMBER_ACCID)) { + ShowError("buildin_getpartymember: Target argument is not an int variable\n"); + script->reportdata(data); + st->state = END; + return false; + } - if ( p != NULL) { - int i; - for (i = 0; i < MAX_PARTY; i++) { - if(p->party.member[i].account_id) { + if (!is_string_variable(varname) && type == PT_MEMBER_NAME) { + ShowError("buildin_getpartymember: Target argument is not a string variable\n"); + script->reportdata(data); + st->state = END; + return false; + } + + if (not_server_variable(*varname)) { + sd = script->rid2sd(st); + + if (sd == NULL) { + script_pushint(st, 0); + return true; // player variable but no player attached + } + } + + if (p != NULL) { + for (int i = 0; i < MAX_PARTY; i++) { + if (p->party.member[i].account_id != 0) { switch (type) { - case 2: - mapreg->setreg(reference_uid(script->add_variable("$@partymemberaid"), j),p->party.member[i].account_id); - break; - case 1: - mapreg->setreg(reference_uid(script->add_variable("$@partymembercid"), j),p->party.member[i].char_id); - break; - default: - mapreg->setregstr(reference_uid(script->add_variable("$@partymembername$"), j),p->party.member[i].name); + case PT_MEMBER_NAME: + script->set_reg(st, sd, reference_uid(id, num), varname, (const void *)h64BPTRSIZE(p->party.member[i].name), reference_getref(data)); + break; + case PT_MEMBER_CHARID: + script->set_reg(st, sd, reference_uid(id, num), varname, (const void *)h64BPTRSIZE(p->party.member[i].char_id), reference_getref(data)); + break; + case PT_MEMBER_ACCID: + script->set_reg(st, sd, reference_uid(id, num), varname, (const void *)h64BPTRSIZE(p->party.member[i].account_id), reference_getref(data)); + break; } - j++; + num++; } } } - mapreg->setreg(script->add_variable("$@partymembercount"),j); + + script_pushint(st, num); return true; } @@ -10094,44 +10128,76 @@ static BUILDIN(getguildinfo) /*========================================== * Get the information of the members of a guild by type. - * getguildmember {,}; - * @param guild_id: ID of guild - * @param type: - * 0 : name (default) - * 1 : character ID - * 2 : account ID + * getguildmember(, , ); *------------------------------------------*/ static BUILDIN(getguildmember) { - struct guild *g = NULL; - int j = 0; + struct map_session_data *sd = NULL; + struct guild *g = guild->search(script_getnum(st, 2)); + enum guildmember_type type = script_getnum(st, 3); + struct script_data *data = script_getdata(st, 4); + const char *varname = reference_getname(data); + int id = reference_getid(data); + int num = 0; - g = guild->search(script_getnum(st,2)); + if (!data_isreference(data) || reference_toconstant(data)) { + ShowError("buildin_getguildmember: Target argument is not a variable\n"); + script->reportdata(data); + st->state = END; + return false; + } + + if (type < GD_MEMBER_NAME || type > GD_MEMBER_ACCID) { + ShowError("buildin_getguildmember: Invalid type argument\n"); + script->reportdata(data); + st->state = END; + return false; + } - if (g) { - int i, type = 0; + if (!is_int_variable(varname) && (type == GD_MEMBER_CHARID || type == GD_MEMBER_ACCID)) { + ShowError("buildin_getguildmember: Target argument is not an int variable\n"); + script->reportdata(data); + st->state = END; + return false; + } - if (script_hasdata(st,3)) - type = script_getnum(st,3); + if (!is_string_variable(varname) && type == GD_MEMBER_NAME) { + ShowError("buildin_getguildmember: Target argument is not a string variable\n"); + script->reportdata(data); + st->state = END; + return false; + } - for ( i = 0; i < MAX_GUILD; i++ ) { - if ( g->member[i].account_id ) { + if (not_server_variable(*varname)) { + sd = script->rid2sd(st); + + if (sd == NULL) { + script_pushint(st, 0); + return true; // player variable but no player attached + } + } + + if (g != NULL) { + for (int i = 0; i < MAX_GUILD; i++) { + if (g->member[i].account_id != 0) { switch (type) { - case 2: - mapreg->setreg(reference_uid(script->add_variable("$@guildmemberaid"), j),g->member[i].account_id); + case GD_MEMBER_NAME: + script->set_reg(st, sd, reference_uid(id, num), varname, (const void *)h64BPTRSIZE(g->member[i].name), reference_getref(data)); break; - case 1: - mapreg->setreg(reference_uid(script->add_variable("$@guildmembercid"), j), g->member[i].char_id); + case GD_MEMBER_CHARID: + script->set_reg(st, sd, reference_uid(id, num), varname, (const void *)h64BPTRSIZE(g->member[i].char_id), reference_getref(data)); break; - default: - mapreg->setregstr(reference_uid(script->add_variable("$@guildmembername$"), j), g->member[i].name); + case GD_MEMBER_ACCID: + script->set_reg(st, sd, reference_uid(id, num), varname, (const void *)h64BPTRSIZE(g->member[i].account_id), reference_getref(data)); break; } - j++; + num++; } } } - mapreg->setreg(script->add_variable("$@guildmembercount"), j); + + script_pushint(st, num); + return true; } @@ -28867,9 +28933,9 @@ static void script_parse_builtin(void) BUILDIN_DEF(setdialogpos, "ii"), BUILDIN_DEF(setdialogpospercent, "ii"), BUILDIN_DEF(getpartyname,"i"), - BUILDIN_DEF(getpartymember,"i?"), + BUILDIN_DEF(getpartymember,"iir"), BUILDIN_DEF(getpartyleader,"i?"), - BUILDIN_DEF(getguildmember,"i?"), + BUILDIN_DEF(getguildmember,"iir"), BUILDIN_DEF(getguildinfo,"i?"), BUILDIN_DEF(getguildonline, "i?"), BUILDIN_DEF(strcharinfo,"i??"), @@ -30121,6 +30187,16 @@ static void script_hardcoded_constants(void) script->set_constant("SIEGE_TYPE_SE", SIEGE_TYPE_SE, false, false); script->set_constant("SIEGE_TYPE_TE", SIEGE_TYPE_TE, false, false); + script->constdb_comment("guildmember types"); + script->set_constant("GD_MEMBER_NAME", GD_MEMBER_NAME, false, false); + script->set_constant("GD_MEMBER_CHARID", GD_MEMBER_CHARID, false, false); + script->set_constant("GD_MEMBER_ACCID", GD_MEMBER_ACCID, false, false); + + script->constdb_comment("partymember types"); + script->set_constant("PT_MEMBER_NAME", PT_MEMBER_NAME, false, false); + script->set_constant("PT_MEMBER_CHARID", PT_MEMBER_CHARID, false, false); + script->set_constant("PT_MEMBER_ACCID", PT_MEMBER_ACCID, false, false); + script->constdb_comment("guildinfo types"); script->set_constant("GUILDINFO_NAME", GUILDINFO_NAME, false, false); script->set_constant("GUILDINFO_ID", GUILDINFO_ID, false, false); diff --git a/src/map/script.h b/src/map/script.h index ecb4b252e42..e74b5169262 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -619,6 +619,18 @@ enum script_hominfo_types { HOMINFO_MAX }; +enum guildmember_type { + GD_MEMBER_NAME, + GD_MEMBER_CHARID, + GD_MEMBER_ACCID, +}; + +enum partymember_type { + PT_MEMBER_NAME, + PT_MEMBER_CHARID, + PT_MEMBER_ACCID, +}; + /** * Structures **/ diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index 111943308da..0fcf5df4044 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -744,14 +744,14 @@ typedef int (*HPMHOOK_pre_chr_delete_char_sql) (int *char_id); typedef int (*HPMHOOK_post_chr_delete_char_sql) (int retVal___, int char_id); typedef struct DBData (*HPMHOOK_pre_chr_create_online_char_data) (union DBKey *key, va_list args); typedef struct DBData (*HPMHOOK_post_chr_create_online_char_data) (struct DBData retVal___, union DBKey key, va_list args); -typedef void (*HPMHOOK_pre_chr_set_account_online) (int *account_id); -typedef void (*HPMHOOK_post_chr_set_account_online) (int account_id); +typedef void (*HPMHOOK_pre_chr_set_account_online) (int *account_id, bool *standalone); +typedef void (*HPMHOOK_post_chr_set_account_online) (int account_id, bool standalone); typedef void (*HPMHOOK_pre_chr_set_account_offline) (int *account_id); typedef void (*HPMHOOK_post_chr_set_account_offline) (int account_id); typedef void (*HPMHOOK_pre_chr_set_char_charselect) (int *account_id); typedef void (*HPMHOOK_post_chr_set_char_charselect) (int account_id); -typedef void (*HPMHOOK_pre_chr_set_char_online) (bool *is_initializing, int *char_id, int *account_id); -typedef void (*HPMHOOK_post_chr_set_char_online) (bool is_initializing, int char_id, int account_id); +typedef void (*HPMHOOK_pre_chr_set_char_online) (bool *is_initializing, int *char_id, int *account_id, bool *standalone); +typedef void (*HPMHOOK_post_chr_set_char_online) (bool is_initializing, int char_id, int account_id, bool standalone); typedef void (*HPMHOOK_pre_chr_set_char_offline) (int *char_id, int *account_id); typedef void (*HPMHOOK_post_chr_set_char_offline) (int char_id, int account_id); typedef int (*HPMHOOK_pre_chr_db_setoffline) (union DBKey *key, struct DBData **data, va_list ap); @@ -7546,6 +7546,12 @@ typedef bool (*HPMHOOK_pre_pc_auto_exp_insurance) (struct map_session_data **sd) typedef bool (*HPMHOOK_post_pc_auto_exp_insurance) (bool retVal___, struct map_session_data *sd); typedef void (*HPMHOOK_pre_pc_crimson_marker_clear) (struct map_session_data **sd); typedef void (*HPMHOOK_post_pc_crimson_marker_clear) (struct map_session_data *sd); +typedef bool (*HPMHOOK_pre_pc_is_own_skill) (struct map_session_data **sd, uint16 *skill_id); +typedef bool (*HPMHOOK_post_pc_is_own_skill) (bool retVal___, struct map_session_data *sd, uint16 skill_id); +typedef void (*HPMHOOK_pre_pc_clear_existing_cloneskill) (struct map_session_data **sd, bool *clear_vars); +typedef void (*HPMHOOK_post_pc_clear_existing_cloneskill) (struct map_session_data *sd, bool clear_vars); +typedef void (*HPMHOOK_pre_pc_clear_existing_reproduceskill) (struct map_session_data **sd, bool *clear_vars); +typedef void (*HPMHOOK_post_pc_clear_existing_reproduceskill) (struct map_session_data *sd, bool clear_vars); #endif // MAP_PC_H #ifdef MAP_NPC_H /* libpcre */ typedef pcre* (*HPMHOOK_pre_libpcre_compile) (const char **pattern, int *options, const char ***errptr, int **erroffset, const unsigned char **tableptr); diff --git a/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc index bf085d7fd66..b4b3b34645b 100644 --- a/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc @@ -719,14 +719,14 @@ struct DBData HP_chr_create_online_char_data(union DBKey key, va_list args) { } return retVal___; } -void HP_chr_set_account_online(int account_id) { +void HP_chr_set_account_online(int account_id, bool standalone) { int hIndex = 0; if (HPMHooks.count.HP_chr_set_account_online_pre > 0) { - void (*preHookFunc) (int *account_id); + void (*preHookFunc) (int *account_id, bool *standalone); *HPMforce_return = false; for (hIndex = 0; hIndex < HPMHooks.count.HP_chr_set_account_online_pre; hIndex++) { preHookFunc = HPMHooks.list.HP_chr_set_account_online_pre[hIndex].func; - preHookFunc(&account_id); + preHookFunc(&account_id, &standalone); } if (*HPMforce_return) { *HPMforce_return = false; @@ -734,13 +734,13 @@ void HP_chr_set_account_online(int account_id) { } } { - HPMHooks.source.chr.set_account_online(account_id); + HPMHooks.source.chr.set_account_online(account_id, standalone); } if (HPMHooks.count.HP_chr_set_account_online_post > 0) { - void (*postHookFunc) (int account_id); + void (*postHookFunc) (int account_id, bool standalone); for (hIndex = 0; hIndex < HPMHooks.count.HP_chr_set_account_online_post; hIndex++) { postHookFunc = HPMHooks.list.HP_chr_set_account_online_post[hIndex].func; - postHookFunc(account_id); + postHookFunc(account_id, standalone); } } return; @@ -797,14 +797,14 @@ void HP_chr_set_char_charselect(int account_id) { } return; } -void HP_chr_set_char_online(bool is_initializing, int char_id, int account_id) { +void HP_chr_set_char_online(bool is_initializing, int char_id, int account_id, bool standalone) { int hIndex = 0; if (HPMHooks.count.HP_chr_set_char_online_pre > 0) { - void (*preHookFunc) (bool *is_initializing, int *char_id, int *account_id); + void (*preHookFunc) (bool *is_initializing, int *char_id, int *account_id, bool *standalone); *HPMforce_return = false; for (hIndex = 0; hIndex < HPMHooks.count.HP_chr_set_char_online_pre; hIndex++) { preHookFunc = HPMHooks.list.HP_chr_set_char_online_pre[hIndex].func; - preHookFunc(&is_initializing, &char_id, &account_id); + preHookFunc(&is_initializing, &char_id, &account_id, &standalone); } if (*HPMforce_return) { *HPMforce_return = false; @@ -812,13 +812,13 @@ void HP_chr_set_char_online(bool is_initializing, int char_id, int account_id) { } } { - HPMHooks.source.chr.set_char_online(is_initializing, char_id, account_id); + HPMHooks.source.chr.set_char_online(is_initializing, char_id, account_id, standalone); } if (HPMHooks.count.HP_chr_set_char_online_post > 0) { - void (*postHookFunc) (bool is_initializing, int char_id, int account_id); + void (*postHookFunc) (bool is_initializing, int char_id, int account_id, bool standalone); for (hIndex = 0; hIndex < HPMHooks.count.HP_chr_set_char_online_post; hIndex++) { postHookFunc = HPMHooks.list.HP_chr_set_char_online_post[hIndex].func; - postHookFunc(is_initializing, char_id, account_id); + postHookFunc(is_initializing, char_id, account_id, standalone); } } return; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index f0d9f6fa44b..e80185b2477 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -5524,6 +5524,12 @@ struct { struct HPMHookPoint *HP_pc_auto_exp_insurance_post; struct HPMHookPoint *HP_pc_crimson_marker_clear_pre; struct HPMHookPoint *HP_pc_crimson_marker_clear_post; + struct HPMHookPoint *HP_pc_is_own_skill_pre; + struct HPMHookPoint *HP_pc_is_own_skill_post; + struct HPMHookPoint *HP_pc_clear_existing_cloneskill_pre; + struct HPMHookPoint *HP_pc_clear_existing_cloneskill_post; + struct HPMHookPoint *HP_pc_clear_existing_reproduceskill_pre; + struct HPMHookPoint *HP_pc_clear_existing_reproduceskill_post; struct HPMHookPoint *HP_libpcre_compile_pre; struct HPMHookPoint *HP_libpcre_compile_post; struct HPMHookPoint *HP_libpcre_study_pre; @@ -13115,6 +13121,12 @@ struct { int HP_pc_auto_exp_insurance_post; int HP_pc_crimson_marker_clear_pre; int HP_pc_crimson_marker_clear_post; + int HP_pc_is_own_skill_pre; + int HP_pc_is_own_skill_post; + int HP_pc_clear_existing_cloneskill_pre; + int HP_pc_clear_existing_cloneskill_post; + int HP_pc_clear_existing_reproduceskill_pre; + int HP_pc_clear_existing_reproduceskill_post; int HP_libpcre_compile_pre; int HP_libpcre_compile_post; int HP_libpcre_study_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index c78e92b8347..1db410c0803 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -2827,6 +2827,9 @@ struct HookingPointData HookingPoints[] = { { HP_POP(pc->expandInventory, HP_pc_expandInventory) }, { HP_POP(pc->auto_exp_insurance, HP_pc_auto_exp_insurance) }, { HP_POP(pc->crimson_marker_clear, HP_pc_crimson_marker_clear) }, + { HP_POP(pc->is_own_skill, HP_pc_is_own_skill) }, + { HP_POP(pc->clear_existing_cloneskill, HP_pc_clear_existing_cloneskill) }, + { HP_POP(pc->clear_existing_reproduceskill, HP_pc_clear_existing_reproduceskill) }, /* pcre_interface */ { HP_POP(libpcre->compile, HP_libpcre_compile) }, { HP_POP(libpcre->study, HP_libpcre_study) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index 997f92dc306..11abdfdc531 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -73497,6 +73497,85 @@ void HP_pc_crimson_marker_clear(struct map_session_data *sd) { } return; } +bool HP_pc_is_own_skill(struct map_session_data *sd, uint16 skill_id) { + int hIndex = 0; + bool retVal___ = false; + if (HPMHooks.count.HP_pc_is_own_skill_pre > 0) { + bool (*preHookFunc) (struct map_session_data **sd, uint16 *skill_id); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_is_own_skill_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_pc_is_own_skill_pre[hIndex].func; + retVal___ = preHookFunc(&sd, &skill_id); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.pc.is_own_skill(sd, skill_id); + } + if (HPMHooks.count.HP_pc_is_own_skill_post > 0) { + bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, uint16 skill_id); + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_is_own_skill_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_pc_is_own_skill_post[hIndex].func; + retVal___ = postHookFunc(retVal___, sd, skill_id); + } + } + return retVal___; +} +void HP_pc_clear_existing_cloneskill(struct map_session_data *sd, bool clear_vars) { + int hIndex = 0; + if (HPMHooks.count.HP_pc_clear_existing_cloneskill_pre > 0) { + void (*preHookFunc) (struct map_session_data **sd, bool *clear_vars); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_clear_existing_cloneskill_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_pc_clear_existing_cloneskill_pre[hIndex].func; + preHookFunc(&sd, &clear_vars); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.pc.clear_existing_cloneskill(sd, clear_vars); + } + if (HPMHooks.count.HP_pc_clear_existing_cloneskill_post > 0) { + void (*postHookFunc) (struct map_session_data *sd, bool clear_vars); + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_clear_existing_cloneskill_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_pc_clear_existing_cloneskill_post[hIndex].func; + postHookFunc(sd, clear_vars); + } + } + return; +} +void HP_pc_clear_existing_reproduceskill(struct map_session_data *sd, bool clear_vars) { + int hIndex = 0; + if (HPMHooks.count.HP_pc_clear_existing_reproduceskill_pre > 0) { + void (*preHookFunc) (struct map_session_data **sd, bool *clear_vars); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_clear_existing_reproduceskill_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_pc_clear_existing_reproduceskill_pre[hIndex].func; + preHookFunc(&sd, &clear_vars); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.pc.clear_existing_reproduceskill(sd, clear_vars); + } + if (HPMHooks.count.HP_pc_clear_existing_reproduceskill_post > 0) { + void (*postHookFunc) (struct map_session_data *sd, bool clear_vars); + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_clear_existing_reproduceskill_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_pc_clear_existing_reproduceskill_post[hIndex].func; + postHookFunc(sd, clear_vars); + } + } + return; +} /* pcre_interface */ pcre* HP_libpcre_compile(const char *pattern, int options, const char **errptr, int *erroffset, const unsigned char *tableptr) { int hIndex = 0; diff --git a/tools/ci/travis.sh b/tools/ci/travis.sh index 82f8321cda2..518dcb31f5e 100755 --- a/tools/ci/travis.sh +++ b/tools/ci/travis.sh @@ -144,27 +144,32 @@ case "$MODE" in ;; esac +SSL_ARG="" +if [[ $(mysql --version) =~ "MariaDB" ]]; then + SSL_ARG="--ssl=0" +fi + case "$MODE" in createdb) echo "Creating database $DBNAME as $DBUSER..." - mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --execute="CREATE DATABASE $DBNAME;" || aborterror "Unable to create database." + mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG $SSL_ARG --execute="CREATE DATABASE $DBNAME;" || aborterror "Unable to create database." ;; importdb) echo "Importing tables into $DBNAME as $DBUSER..." - mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --database=$DBNAME < sql-files/main.sql || aborterror "Unable to import main database." - mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --database=$DBNAME < sql-files/logs.sql || aborterror "Unable to import logs database." + mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG $SSL_ARG --database=$DBNAME < sql-files/main.sql || aborterror "Unable to import main database." + mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG $SSL_ARG --database=$DBNAME < sql-files/logs.sql || aborterror "Unable to import logs database." ;; adduser) echo "Adding user $NEWUSER as $DBUSER, with access to database $DBNAME..." - mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --execute="GRANT SELECT,INSERT,UPDATE,DELETE ON $DBNAME.* TO '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true - mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --execute="CREATE USER '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true - mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --execute="GRANT SELECT,INSERT,UPDATE,DELETE ON $DBNAME.* TO '$NEWUSER'@'$DBHOST';" || true - mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --execute="ALTER USER '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true + mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG $SSL_ARG --execute="GRANT SELECT,INSERT,UPDATE,DELETE ON $DBNAME.* TO '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true + mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG $SSL_ARG --execute="CREATE USER '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true + mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG $SSL_ARG --execute="GRANT SELECT,INSERT,UPDATE,DELETE ON $DBNAME.* TO '$NEWUSER'@'$DBHOST';" || true + mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG $SSL_ARG --execute="ALTER USER '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true if [[ -n "$(uname -a | grep -i linux)" ]]; then - mysql --defaults-file=/etc/mysql/debian.cnf $DBPASS_ARG $DBHOST_ARG --execute="CREATE USER '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true - mysql --defaults-file=/etc/mysql/debian.cnf $DBPASS_ARG $DBHOST_ARG --execute="GRANT SELECT,INSERT,UPDATE,DELETE ON $DBNAME.* TO '$NEWUSER'@'$DBHOST';" || true - mysql --defaults-file=/etc/mysql/debian.cnf $DBPASS_ARG $DBHOST_ARG --execute="ALTER USER '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true + mysql --defaults-file=/etc/mysql/debian.cnf $DBPASS_ARG $DBHOST_ARG $SSL_ARG --execute="CREATE USER '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true + mysql --defaults-file=/etc/mysql/debian.cnf $DBPASS_ARG $DBHOST_ARG $SSL_ARG --execute="GRANT SELECT,INSERT,UPDATE,DELETE ON $DBNAME.* TO '$NEWUSER'@'$DBHOST';" || true + mysql --defaults-file=/etc/mysql/debian.cnf $DBPASS_ARG $DBHOST_ARG $SSL_ARG --execute="ALTER USER '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';" || true fi ;; build)