Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fbb82ac
feat(core): add database player concurrency lock to prevent web/game …
berrytern Aug 18, 2026
fd68403
fix(core): improve lock expiration with db timestamp and fix config s…
berrytern Aug 18, 2026
5ea9b4b
feat(schema): add migration 64 for player concurrency lock columns an…
berrytern Aug 19, 2026
964705d
fix(core): use int64_t for lock timestamps and bound future timestamp…
berrytern Aug 19, 2026
5d9b741
Merge branch 'main' into feat/player-concurrency-lock
berrytern Aug 19, 2026
a9480ed
style(migrations): format migration 64 with StyLua
berrytern Aug 19, 2026
960d43d
chore(schema): update db_version to 64 in schema.sql
berrytern Aug 19, 2026
d1f58fe
feat(market): add asynchronous web market order queue processor (IOMa…
berrytern Aug 18, 2026
72ca571
fix(market): use async db task, getPlayerByGUID, and native inbox del…
berrytern Aug 18, 2026
734611a
fix(market): fix tier use-after-free, add world_id scoping, refund ro…
berrytern Aug 19, 2026
4697114
style: format Lua and C++ files according to StyLua and Clang-Format
berrytern Aug 19, 2026
26b8f4f
chore(schema): update db_version to 65 in schema.sql
berrytern Aug 19, 2026
dc9d1f0
fix(market): include missing headers in iomarket.cpp for non-unity de…
berrytern Aug 20, 2026
f4f0a1d
fix: soul cores (#910)
Paco161315 Aug 20, 2026
3bb423e
fix: register the !time talkaction (#913)
aacruzgon Aug 20, 2026
7e9251b
fix(market): include missing account enum headers in iomarket.cpp for…
berrytern Aug 21, 2026
bbf2940
fix: vcpkg path setup for MSBuild (#916)
jprzimba Aug 21, 2026
ff0bd38
fix: gold exploit on bow and inkwell NPC prices (#914)
aacruzgon Aug 21, 2026
907ea1b
update: the new frontier quest (#900)
Paco161315 Aug 22, 2026
4ec61be
fix: DBResult::getNumber returns 0 for time_t on macOS (#911)
aacruzgon Aug 22, 2026
170009f
feat: macOS build support (#912)
aacruzgon Aug 22, 2026
6be8396
feat: multi world system (#451)
jprzimba Aug 22, 2026
a0c3a47
update: Document multiworld setup
jprzimba Aug 22, 2026
711c363
ci: add macOS build workflow (#924)
aacruzgon Aug 23, 2026
adb8c15
chore: ignore macOS .DS_Store files (#923)
aacruzgon Aug 23, 2026
ceab1f7
fix(game): compare zone type instead of negating it when leaving a pa…
aacruzgon Aug 24, 2026
a89d7c5
fix(database): persist db_version globally instead of per-world (#921)
aacruzgon Aug 24, 2026
4cf3cbf
fix: Rookgaard status healing npcs (#920)
Paco161315 Aug 24, 2026
c44920a
fix: pugi::cast<float> does not compile with libc++ (#926)
aacruzgon Aug 26, 2026
9f09677
fix: load map items with decay (#915)
GuiValladao Aug 26, 2026
63908be
feat: The Isle of Evil Quest (#919)
GuiValladao Aug 26, 2026
cf22fe3
feat: char bazaar auction setup from the game client (#918)
htc16 Aug 28, 2026
cbb6da4
fix: Revert lua format (#928)
jprzimba Aug 28, 2026
2088a74
update: doors table (#930)
Paco161315 Sep 9, 2026
01f51c8
fix: Hirelings load (#933)
jprzimba Sep 10, 2026
f31dbde
update: dire penguin raids (#931)
Paco161315 Sep 11, 2026
a9badcb
feat: declare map ids and container contents in the tables (#932)
htc16 Sep 11, 2026
5d71408
fix: Use FAMILIARSNAME constant for familiar check
jprzimba Sep 11, 2026
7884cfe
fix: resolve startup entry and lever conflicts reported by the map id…
htc16 Sep 11, 2026
abcc843
fix: pits of inferno bosses (#939)
Paco161315 Sep 14, 2026
7860e6a
feat(look): name the script that answers for an item (#938)
htc16 Sep 14, 2026
f773940
fix: Initialize player cooldown timers on login (#935)
jprzimba Sep 15, 2026
ff7ede5
feat(core): add database player concurrency lock to prevent web/game …
berrytern Sep 16, 2026
30979a6
fix: Stop reseeding RNG in DropLoot (#934)
jprzimba Sep 18, 2026
8ffaedb
Merge remote-tracking branch 'berrytern/feat/web-market-order-queue' …
jprzimba Sep 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/build-macos-dummy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: Build - macOS (dummy)

on:
workflow_dispatch:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths-ignore:
- "src/**"

jobs:
job:
if: ${{ github.event_name == 'push' || !github.event.pull_request.draft }}
name: ${{ matrix.os }}-${{ matrix.buildtype }}
# The check name is what branch protection matches, not the runner, so this
# stays on Ubuntu instead of spending four macOS runners on an echo.
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
os: [macos-15]
buildtype: [macos-release, macos-debug]

steps:
- run: echo "This is a dummy job to satisfy branch protection checks"
- name: Checkout repository
uses: actions/checkout@main
101 changes: 101 additions & 0 deletions .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
name: Build - macOS

on:
workflow_dispatch:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- "src/**"
merge_group:
push:
paths:
- "src/**"
branches:
- main

env:
CMAKE_BUILD_PARALLEL_LEVEL: 3
MAKEFLAGS: "-j 3"

jobs:
cancel-runs:
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}

job:
if: ${{ github.event_name == 'push' || !github.event.pull_request.draft }}
name: ${{ matrix.os }}-${{ matrix.buildtype }}
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
# macos-14 defaults to Xcode 15.4, whose clang predates P0960
# (parenthesized aggregate init) and fails on make_shared/emplace_back of
# plain structs. Nothing in the tree needs it, so the matrix stays on 15.
os: [macos-15]
buildtype: [macos-release, macos-debug]
include:
- os: macos-15
triplet: arm64-osx

steps:
- name: Checkout repository
uses: actions/checkout@main

# vcpkg builds gmp from source on macOS and its build system needs
# autotools, which the runner image does not guarantee.
- name: Install macOS Dependencies
run: |
for pkg in autoconf automake libtool; do
brew list --formula "$pkg" >/dev/null 2>&1 || brew install "$pkg"
done

- name: CCache
uses: hendrikmuhs/ccache-action@main
with:
max-size: "1G"
key: ccache-${{ matrix.os }}-${{ matrix.buildtype }}
restore-keys: |
ccache-${{ matrix.os }}

- name: Restore artifacts and install vcpkg
id: vcpkg-step
run: |
vcpkgCommitId=$(grep '.builtin-baseline' vcpkg.json | awk -F: '{print $2}' | tr -d '," ')
echo "vcpkg commit ID: $vcpkgCommitId"
echo "VCPKG_GIT_COMMIT_ID=$vcpkgCommitId" >> "$GITHUB_ENV"

- name: Get vcpkg commit id from vcpkg.json
uses: lukka/run-vcpkg@main
with:
vcpkgGitURL: "https://github.com/microsoft/vcpkg.git"
vcpkgGitCommitId: ${{ env.VCPKG_GIT_COMMIT_ID }}

- name: Get latest CMake and ninja
uses: lukka/get-cmake@main

- name: Run CMake
uses: lukka/run-cmake@main
with:
configurePreset: ${{ matrix.buildtype }}
buildPreset: ${{ matrix.buildtype }}
configurePresetAdditionalArgs: "['-DBUILD_TESTS=ON']"

- name: Create and Upload Artifact
uses: actions/upload-artifact@main
with:
name: crystalserver-${{ matrix.os }}-${{ matrix.buildtype }}-${{ github.sha }}
path: |
${{ github.workspace }}/build/${{ matrix.buildtype }}/bin/

- name: Run Unit Tests
run: |
cd ${{ github.workspace }}/build/${{ matrix.buildtype }}/tests/unit
ctest --verbose
2 changes: 1 addition & 1 deletion .github/workflows/lua-format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ jobs:
author_email: github-actions[bot]@users.noreply.github.com
message: "Lua code format - (Stylua)"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,6 @@ database_backup
# CLION
cmake-build-*
/data/logs

# macOS
.DS_Store
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ endif()
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)

# Configure build options for compatibility with commodity CPUs
if(NOT MSVC)
if(NOT MSVC AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64|i[3-6]86)$")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -mtune=generic -mno-avx -mno-sse4")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=x86-64 -mtune=generic -mno-avx -mno-sse4")
endif()
Expand Down
38 changes: 38 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,36 @@
"cacheVariables": {
"BUILD_TESTS": "ON"
}
},
{
"name": "macos-release",
"inherits": "base",
"displayName": "macOS - Release",
"description": "macOS Release Build (Apple Silicon or Intel)",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": {
"value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"type": "FILEPATH"
},
"RUN_TESTS_AFTER_BUILD": "OFF"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
}
},
{
"name": "macos-debug",
"inherits": "macos-release",
"displayName": "macOS - Debug Build",
"description": "Build Debug Mode",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"DEBUG_LOG": "ON",
"SPEED_UP_BUILD_UNITY": "OFF"
}
}
],
"buildPresets": [
Expand All @@ -134,6 +164,14 @@
{
"name": "windows-Xdebug",
"configurePreset": "windows-debug"
},
{
"name": "macos-release",
"configurePreset": "macos-release"
},
{
"name": "macos-debug",
"configurePreset": "macos-debug"
}
]
}
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ at [this link](https://github.com/zimbadev/crystalserver/blob/main/CODE_OF_CONDU

You can use your own tool to generate Monster Loot and Monster Elements at [this link](https://crystalsever.vercel.app).

### Multi Wworld
For information about the Multi Wworld system, see [MULTIWORLD.md](markdowns/MULTIWORLD.md).

### Official Discord
Enjoy our [Discord](https://discord.gg/zm4MTKtQQh)

Expand Down
23 changes: 17 additions & 6 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ toggleMaintainMode = false
-- @field [parent=#global] #string maintainModeMessage an empty string by default, set a custom message if needed.
maintainModeMessage = ""

-- World settings (This information will be loaded from the 'worlds' database table as well)
-- NOTE: World id is 1 as default, new worlds must have different ids always greater than 1
-- NOTE: valid values for worldType are: "pvp", "no-pvp", "pvp-enforced", "retro-pvp" and "retro-hardcore"
-- NOTE: valid values for worldLocation are: "Europe", "North America", "South America" and "Oceania"
worldId = 1
worldType = "pvp"
worldLocation = "South America"

-- Combat settings
-- NOTE: valid values for worldType are: "pvp", "no-pvp" and "pvp-enforced"
-- NOTE: removeBeginningWeaponAmmunition: spears, arrows, bolt have endless ammo (allows training for paladins)
-- NOTE: refundManaOnBeginningWeapons: wand of vortex and snakebite refund mana used (allows training for mages)
worldType = "pvp"
hotkeyAimbotEnabled = true
protectionLevel = 7
pzLocked = 60 * 1000
Expand Down Expand Up @@ -80,7 +86,7 @@ allowOldProtocol = false
bindOnlyGlobalAddress = false
loginProtocolPort = 7171
gameProtocolPort = 7172
statusProtocolPort = 7171
statusProtocolPort = 97172
maxPlayers = 0
serverName = "Crystal"
serverMotd = "Welcome to the Crystal Server!"
Expand All @@ -92,6 +98,12 @@ maxPlayersOutsidePZPerAccount = 1
toggleMaxConnectionsByIP = false
maxIPConnections = 3

-- Player Concurrency Lock
-- NOTE: togglePlayerLock blocks character logins during web transactions (marketplace, admin changes, character bazaar)
-- NOTE: playerLockTimeout defines the lock expiry in seconds to prevent deadlock if a web request fails
togglePlayerLock = true
playerLockTimeout = 60

-- Packet Compression
-- Minimize network bandwith and reduce ping
-- Levels: 0 = disabled, 1 = best speed, 9 = best compression
Expand Down Expand Up @@ -306,7 +318,6 @@ onlyPremiumAccount = false
-- NOTE: autoBank = true, the dropped coins from monsters will be automatically deposited to your bank account.
-- NOTE: toggleGoldPouchAllowAnything will allow players to move items or gold to gold pouch
-- NOTE: toggleGoldPouchQuickLootOnly will ONLY allow quickloot to move items to gold pouch
-- NOTE: toggleServerIsRetroPVP will make this server as retro, setting PARTY_PROTECTION and ADVANCED_SECURE_MODE to 0
-- NOTE: toggleTravelsFree will make all travels from boat free
-- NOTE: buyAolCommandFee will add fee when player buy aol by command (!aol), active changing value more than 0 (fee value. ex: 1 = 1gp aol will be 50001)
-- NOTE: teleportPlayerToVocationRoom will enable oressa to teleport player to his/her room vocation
Expand All @@ -323,7 +334,6 @@ autoLoot = false
autoBank = false
toggleGoldPouchAllowAnything = false
toggleGoldPouchQuickLootOnly = false
toggleServerIsRetroPVP = false
toggleTravelsFree = false
buyAolCommandFee = 0
teleportPlayerToVocationRoom = true
Expand Down Expand Up @@ -482,6 +492,8 @@ marketRefreshPricesInterval = 30
premiumToCreateMarketOffer = true
checkExpiredMarketOffersEachMinutes = 60
maxMarketOffersAtATimePerPlayer = 100
toggleWebMarketOrders = true
webMarketOrdersInterval = 2000

-- MySQL
-- NOTE: mysqlPoolSize 4 (default) — small to medium servers
Expand Down Expand Up @@ -679,7 +691,6 @@ startupDatabaseOptimization = true
ownerName = "Tryller"
ownerEmail = "@gmail.com"
url = "https://github.com/zimbadev/crystalserver"
location = "South America"

-- Sends Discord webhook notifications on startup, raids and shutdown.
-- The URL layout is https://discord.com/api/webhooks/:id/:token
Expand Down
98 changes: 98 additions & 0 deletions data-global/lib/core/quests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7550,5 +7550,103 @@ if not Quests then
},
},
},
[58] = {
name = "The Isle Of Evil",
startStorageId = Storage.Quest.U8_5.TheIsleOfEvil.Questline,
startStorageValue = 1,
missions = {
[1] = {
name = "Hired",
storageId = Storage.Quest.U8_5.ShadowsOfYalahar.Mission13,
missionId = 11036,
startValue = 0,
endValue = 1,
description = "You are hired .. sort of. Speak to Rapanaio about your first mission to help him.",
},
[2] = {
name = "Mission 01: Just A Fishing Trip",
storageId = Storage.Quest.U8_5.TheIsleOfEvil.Mission01,
missionId = 11037,
startValue = 1,
endValue = 2,
states = {
[1] = "Rapanaio wants a mechanical fish. Travel to sewers of Yalahar and use your mechanical fishing rod along with some nails as bait to tactch one. Return that fish to Rapanaio for examination.You have delivered a mechanical fish to Rapanaio and are ready for your next mission.",
[2] = "You have delivered the mechanical fish to Rapanaio.",
},
},
[3] = {
name = "Mission 02: A Potent Fuel",
storageId = Storage.Quest.U8_5.TheIsleOfEvil.Mission02,
missionId = 11038,
startValue = 1,
endValue = 2,
states = {
[1] = "Rapanaio needs 10 vials filled with rum as fuel for his ominous invention.",
[2] = "You have delivered 10 instances of rum to Rapanaio... and pray he actually saves it as fuel.",
},
},
[4] = {
name = "Mission 03: Something Sweet",
storageId = Storage.Quest.U8_5.TheIsleOfEvil.Mission03,
missionId = 11039,
startValue = 1,
endValue = 2,
states = {
[1] = "Rapanaio urgently wants one vial of fruit juice. You better hurry, else his invention might be in danger.",
[2] = "Rapanaio got the juice he requested just in time... to quench his thirst.",
},
},
[5] = {
name = "Mission 04: The Technomancer's Machine",
storageId = Storage.Quest.U8_5.TheIsleOfEvil.Mission04,
missionId = 11040,
startValue = 1,
endValue = 5,
states = {
[1] = "Rapanaio has asked you to get him a machina from his old acquaintance Scutty of the technomancers' guild in Kazordoon.",
[2] = "Scutty asked you to scared away 6 carrion worms. Take caro to don't hit his ordinary worms!",
[3] = "You have gotten the machine from Scutty and can deliver it to Rapanaio.",
[4] = "You received the machine from Scutty. Go deliver it to Rapanaio.",
[5] = "You have delivered the machine from Scutty to Rapanaio.",
},
},
[6] = {
name = "Mission 05: The Map To Evil",
storageId = Storage.Quest.U8_5.TheIsleOfEvil.Mission05,
missionId = 11041,
startValue = 1,
endValue = 3,
states = {
[1] = "Rapanaio needs a nautical map from the Explorer Society. Ask about one at their base northeast of Carlin.",
[2] = "Mortimer advised you to look for the map in a cave to the east.",
[3] = "You have delivered the Nautical Map to Rapanaio.",
},
},
[7] = {
name = "Mission 06: The Secret",
storageId = Storage.Quest.U8_5.TheIsleOfEvil.Mission06,
missionId = 11042,
startValue = 1,
endValue = 2,
states = {
[1] = "Rapanaio has asked you to meet him downstairs where he will reveal his invention. Surely absolutely nothing can happen to you in some dwarf's cellar and you should be perfectly safe... probably.",
[2] = "You have now seen Rapanaio's invention - an underwater boat of dubious design. He has rather reluctantly transported you to the Isle of Evil. You should talk to him about the next step in his plan.",
},
},
[8] = {
name = "Mission 07: The Master Of Evil",
storageId = Storage.Quest.U8_5.TheIsleOfEvil.Mission07,
missionId = 11043,
startValue = 1,
endValue = 4,
states = {
[1] = "Now that you finally arrived on the Isle of Evil it's your duty to slay the master of this isle. Make sure to use his corpse to find prof of your accomplishment. Rapanaio will await your return.",
[2] = "You killed every threat on the island of evil. Talk to Rapanaio about it.",
[3] = "You have finally braved the perils of the Isle of Evil. Now you should follow Rapanaio's suggestion and speak to King Tibianus in Thais about that membership card.",
[4] = "You spoke with King Tibianus about the membership card.",
},
},
},
},
}
end
Loading
Loading