port: P3-c PythonExchange + exchange module (1:1 40250)

Copy PythonExchange.cpp/PythonExchangeModule.cpp verbatim, drop the pending
stand-in and the exchange module stub, register initTrade() after
initNonPlayer(). The fake server answers CG_EXCHANGE START with the partner's
item + gold and CANCEL with END; port.login_flow drives the exchange round-trip
through the Python exchange/net modules and uiexchange.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-24 00:59:05 +09:00
co-authored by Claude Opus 5.5
parent 9298500df9
commit 72b19b677d
14 changed files with 853 additions and 162 deletions
+1
View File
@@ -532,3 +532,4 @@
{"time": "2026-09-24T05:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P2: ServerStateChecker + module", "ported": ["UserInterface/ServerStateChecker.cpp", "UserInterface/ServerStateCheckerModule.cpp"], "adapted": [], "divergent": [], "needs_live": [], "tests": ["port.login_flow: fake state port answers CG_STATE_CHECKER, NotifyChannelState(2, 1)", "port.login_live 192.168.21.203: channel states {1: 1, 2: 1}", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3 item chain: ItemData, ItemManager, PythonItem, PythonExchange"]} {"time": "2026-09-24T05:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P2: ServerStateChecker + module", "ported": ["UserInterface/ServerStateChecker.cpp", "UserInterface/ServerStateCheckerModule.cpp"], "adapted": [], "divergent": [], "needs_live": [], "tests": ["port.login_flow: fake state port answers CG_STATE_CHECKER, NotifyChannelState(2, 1)", "port.login_live 192.168.21.203: channel states {1: 1, 2: 1}", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3 item chain: ItemData, ItemManager, PythonItem, PythonExchange"]}
{"time": "2026-09-24T06:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-a: ItemData, ItemManager, PythonNonPlayer + LoadLocaleData", "ported": ["GameLib/ItemData.cpp", "GameLib/ItemManager.cpp", "UserInterface/PythonNonPlayer.cpp", "UserInterface/PythonNonPlayerModule.cpp"], "adapted": ["UserInterface/PythonApplication.cpp:LoadLocaleData"], "divergent": [], "needs_live": [], "tests": ["port.login_flow 3c: item 19 Sword+9 type 1 refine 9, mob 101 Wild Dog", "port.login_live 192.168.21.203: same", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3-b PythonItem + PythonItemModule", "CPythonSkill (RegisterSkillDesc/Table) still pending"]} {"time": "2026-09-24T06:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-a: ItemData, ItemManager, PythonNonPlayer + LoadLocaleData", "ported": ["GameLib/ItemData.cpp", "GameLib/ItemManager.cpp", "UserInterface/PythonNonPlayer.cpp", "UserInterface/PythonNonPlayerModule.cpp"], "adapted": ["UserInterface/PythonApplication.cpp:LoadLocaleData"], "divergent": [], "needs_live": [], "tests": ["port.login_flow 3c: item 19 Sword+9 type 1 refine 9, mob 101 Wild Dog", "port.login_live 192.168.21.203: same", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3-b PythonItem + PythonItemModule", "CPythonSkill (RegisterSkillDesc/Table) still pending"]}
{"time": "2026-09-24T07:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-b: PythonItem + PythonItemModule", "ported": ["UserInterface/PythonItem.cpp", "UserInterface/PythonItemModule.cpp"], "adapted": ["UserInterface/PythonItemModule.cpp:itemGetIconImage", "GameLib/MapManager.cpp:CMapManager::GetNormal"], "divergent": [], "needs_live": [], "tests": ["port.login_flow: fake GC_ITEM_GROUND_ADD vnum 19 + ownership, player.PickCloseItem -> CG_ITEM_PICKUP -> GC_ITEM_GROUND_DEL removes it", "port.login_flow: item.SelectItem(19) name/type/subtype/value", "port.login_live 192.168.21.203: passes (icon pointer truncation segfault fixed)", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3-c PythonExchange", "PythonTextTail item tails (Register/Delete/SetOwner/Pick still stubs)", "CEffectManager (dropitem.mse)"]} {"time": "2026-09-24T07:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-b: PythonItem + PythonItemModule", "ported": ["UserInterface/PythonItem.cpp", "UserInterface/PythonItemModule.cpp"], "adapted": ["UserInterface/PythonItemModule.cpp:itemGetIconImage", "GameLib/MapManager.cpp:CMapManager::GetNormal"], "divergent": [], "needs_live": [], "tests": ["port.login_flow: fake GC_ITEM_GROUND_ADD vnum 19 + ownership, player.PickCloseItem -> CG_ITEM_PICKUP -> GC_ITEM_GROUND_DEL removes it", "port.login_flow: item.SelectItem(19) name/type/subtype/value", "port.login_live 192.168.21.203: passes (icon pointer truncation segfault fixed)", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3-c PythonExchange", "PythonTextTail item tails (Register/Delete/SetOwner/Pick still stubs)", "CEffectManager (dropitem.mse)"]}
{"time": "2026-09-24T08:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-c: PythonExchange + PythonExchangeModule", "ported": ["UserInterface/PythonExchange.cpp", "UserInterface/PythonExchangeModule.cpp"], "adapted": [], "divergent": [], "needs_live": ["exchange with a real second player"], "tests": ["port.login_flow: net.SendExchangeStartPacket -> fake GC_EXCHANGE START/ITEM_ADD/GOLD_ADD fills target side, uiexchange opens; SendExchangeExitPacket -> END closes", "port.login_live 192.168.21.203: passes", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["PythonTextTail item tails", "PythonMiniMap", "CEffectManager", "CPythonSkill"]}
@@ -0,0 +1,224 @@
{
"reference": "UserInterface/PythonExchange.cpp",
"reference_sha256": "ed8529ffd11f1baafe7c2cc0e83d1480ecb28df69ad74aa94813223371600a2e",
"priority": "P3",
"contracts": [],
"functions": {
"CPythonExchange::SetSelfName": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetSelfName"
]
},
"CPythonExchange::SetTargetName": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetTargetName"
]
},
"CPythonExchange::GetNameFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetNameFromSelf"
]
},
"CPythonExchange::GetNameFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetNameFromTarget"
]
},
"CPythonExchange::SetElkToTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetElkToTarget"
]
},
"CPythonExchange::SetElkToSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetElkToSelf"
]
},
"CPythonExchange::GetElkFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetElkFromTarget"
]
},
"CPythonExchange::GetElkFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetElkFromSelf"
]
},
"CPythonExchange::SetItemToTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetItemToTarget"
]
},
"CPythonExchange::SetItemToSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetItemToSelf"
]
},
"CPythonExchange::SetItemMetinSocketToTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetItemMetinSocketToTarget"
]
},
"CPythonExchange::SetItemMetinSocketToSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetItemMetinSocketToSelf"
]
},
"CPythonExchange::SetItemAttributeToTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetItemAttributeToTarget"
]
},
"CPythonExchange::SetItemAttributeToSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetItemAttributeToSelf"
]
},
"CPythonExchange::DelItemOfTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::DelItemOfTarget"
]
},
"CPythonExchange::DelItemOfSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::DelItemOfSelf"
]
},
"CPythonExchange::GetItemVnumFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetItemVnumFromTarget"
]
},
"CPythonExchange::GetItemVnumFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetItemVnumFromSelf"
]
},
"CPythonExchange::GetItemCountFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetItemCountFromTarget"
]
},
"CPythonExchange::GetItemCountFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetItemCountFromSelf"
]
},
"CPythonExchange::GetItemMetinSocketFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetItemMetinSocketFromTarget"
]
},
"CPythonExchange::GetItemMetinSocketFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetItemMetinSocketFromSelf"
]
},
"CPythonExchange::GetItemAttributeFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetItemAttributeFromTarget"
]
},
"CPythonExchange::GetItemAttributeFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetItemAttributeFromSelf"
]
},
"CPythonExchange::SetAcceptToTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetAcceptToTarget"
]
},
"CPythonExchange::SetAcceptToSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetAcceptToSelf"
]
},
"CPythonExchange::GetAcceptFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetAcceptFromTarget"
]
},
"CPythonExchange::GetAcceptFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetAcceptFromSelf"
]
},
"CPythonExchange::GetElkMode": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::GetElkMode"
]
},
"CPythonExchange::SetElkMode": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::SetElkMode"
]
},
"CPythonExchange::Start": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::Start"
]
},
"CPythonExchange::End": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::End"
]
},
"CPythonExchange::isTrading": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::isTrading"
]
},
"CPythonExchange::Clear": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::Clear"
]
},
"CPythonExchange::CPythonExchange": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::CPythonExchange"
]
},
"CPythonExchange::~CPythonExchange": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchange.cpp:CPythonExchange::~CPythonExchange"
]
}
}
}
@@ -0,0 +1,122 @@
{
"reference": "UserInterface/PythonExchangeModule.cpp",
"reference_sha256": "90fb936b2f2ac29833083fd69a2c5f4307c65eda153b6f02214942d765bdb143",
"priority": "P3",
"contracts": [],
"functions": {
"exchangeInitTrading": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeInitTrading"
]
},
"exchangeisTrading": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeisTrading"
]
},
"exchangeGetElkFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetElkFromSelf"
]
},
"exchangeGetElkFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetElkFromTarget"
]
},
"exchangeGetAcceptFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetAcceptFromSelf"
]
},
"exchangeGetAcceptFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetAcceptFromTarget"
]
},
"exchangeGetItemVnumFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetItemVnumFromSelf"
]
},
"exchangeGetItemVnumFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetItemVnumFromTarget"
]
},
"exchangeGetItemCountFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetItemCountFromSelf"
]
},
"exchangeGetItemCountFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetItemCountFromTarget"
]
},
"exchangeGetNameFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetNameFromSelf"
]
},
"exchangeGetNameFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetNameFromTarget"
]
},
"exchangeGetItemMetinSocketFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetItemMetinSocketFromTarget"
]
},
"exchangeGetItemMetinSocketFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetItemMetinSocketFromSelf"
]
},
"exchangeGetItemAttributeFromTarget": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetItemAttributeFromTarget"
]
},
"exchangeGetItemAttributeFromSelf": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetItemAttributeFromSelf"
]
},
"exchangeGetElkMode": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeGetElkMode"
]
},
"exchangeSetElkMode": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:exchangeSetElkMode"
]
},
"initTrade": {
"status": "PORTED",
"impl": [
"extension/src/port/UserInterface/PythonExchangeModule.cpp:initTrade"
]
}
}
}
+2
View File
@@ -438,6 +438,8 @@ extension/third_party/cpython-2.7.18/ # 静态库(2P 批次
P3-b(2026-09-24):`PythonItem.cpp` 与 `PythonItemModule.cpp` 原样移植,删除 pending 替身与 item 模块桩,`initItem()` 按 40250 顺序在 `initPlayer()` 之后;平台 `CPythonApplication::Create` 按原序调 `m_pyItem.Create()`(dropitem.mse 注册仍落在 CEffectManager 桩)。改动:`itemGetIconImage` 用 `Py_BuildPointer` 返回图标指针(40250 ILP32 用 `"i"`,64 位下被截断,真服背包 `wndMgr.SetSlot` 段错误);`D3DXMath.h` 补 `D3DXQuaternionConjugate`;pending `CMapManager::GetNormal` 以 `CTerrain::CalculateNormal` 公式按需在高度块上算法线;`CPythonTextTail` 的物品名牌四函数暂为桩,`Pick` 按 40250 空表语义返回 -1(返回 0 会把地面物品 VID 0 当作选中,点地移动失效)。假服入场时按 `CItem::EncodeInsertPacket` 发 vnum 19 的 `GC_ITEM_GROUND_ADD`+`GC_ITEM_OWNERSHIP`,收到 `CG_ITEM_PICKUP` 回 `GC_ITEM_GROUND_DEL`;`port.login_flow` 验证地面物品位置/归属/vnum,`player.PickCloseItem()` 发出拾取、物品被删除,以及 `item.SelectItem(19)` 的名称/类型/子类型/数值。下一步 P3-c:`PythonExchange`,之后 `PythonTextTail`(物品名牌)与 `PythonMiniMap`。 P3-b(2026-09-24):`PythonItem.cpp` 与 `PythonItemModule.cpp` 原样移植,删除 pending 替身与 item 模块桩,`initItem()` 按 40250 顺序在 `initPlayer()` 之后;平台 `CPythonApplication::Create` 按原序调 `m_pyItem.Create()`(dropitem.mse 注册仍落在 CEffectManager 桩)。改动:`itemGetIconImage` 用 `Py_BuildPointer` 返回图标指针(40250 ILP32 用 `"i"`,64 位下被截断,真服背包 `wndMgr.SetSlot` 段错误);`D3DXMath.h` 补 `D3DXQuaternionConjugate`;pending `CMapManager::GetNormal` 以 `CTerrain::CalculateNormal` 公式按需在高度块上算法线;`CPythonTextTail` 的物品名牌四函数暂为桩,`Pick` 按 40250 空表语义返回 -1(返回 0 会把地面物品 VID 0 当作选中,点地移动失效)。假服入场时按 `CItem::EncodeInsertPacket` 发 vnum 19 的 `GC_ITEM_GROUND_ADD`+`GC_ITEM_OWNERSHIP`,收到 `CG_ITEM_PICKUP` 回 `GC_ITEM_GROUND_DEL`;`port.login_flow` 验证地面物品位置/归属/vnum,`player.PickCloseItem()` 发出拾取、物品被删除,以及 `item.SelectItem(19)` 的名称/类型/子类型/数值。下一步 P3-c:`PythonExchange`,之后 `PythonTextTail`(物品名牌)与 `PythonMiniMap`。
P3-c(2026-09-24):`PythonExchange.cpp` 与 `PythonExchangeModule.cpp` 原样移植(无手改),删除 pending 替身与 exchange 模块桩,`initTrade()` 按 40250 顺序在 `initNonPlayer()` 之后。假服按 `CInputMain::Exchange` 应答:`CG_EXCHANGE` START 回 `GC_EXCHANGE` START(arg1 = 请求的 vid)+ 对方 ITEM_ADD(vnum 19,格 0)+ GOLD_ADD 1000,CANCEL 回 END;`port.login_flow` 用 `net.SendExchangeStartPacket` 开交易,验证 `exchange.isTrading/GetItemVnumFromTarget/GetItemCountFromTarget/GetElkFromTarget`,uiexchange 打开后 `net.SendExchangeExitPacket` 收到 END 关闭。注意:40250 `SendExchangeExitPacket` 的 arg1 未初始化(原样保留,假服不记录它);`uiexchange.CloseDialog` 调 `wndMgr.OnceIgnoreMouseLeftButtonUpEvent()`,测试先消耗这次被忽略的左键抬起,否则下一次点地的抬起被吞、角色一直按住行走。下一步 `PythonTextTail`(物品名牌)与 `PythonMiniMap`。
每个切片都必须同时跑 legacy/port 双路回归;只有 2V3 稳定并把默认路由切到 `port` 后,才能删除总开关和剩余 legacy 宿主。 每个切片都必须同时跑 legacy/port 双路回归;只有 2V3 稳定并把默认路由切到 `port` 后,才能删除总开关和剩余 legacy 宿主。
## 5. 数据源切换:m2dev assets → 40250 ## 5. 数据源切换:m2dev assets → 40250
@@ -81,13 +81,6 @@ void AddStubConstants_eventMgr(PyObject* poModule)
(void) poModule; (void) poModule;
} }
// 40250 UserInterface/PythonExchangeModule.cpp
void AddStubConstants_exchange(PyObject* poModule)
{
(void) poModule;
PyModule_AddIntConstant(poModule, "EXCHANGE_ITEM_MAX_NUM", CPythonExchange::EXCHANGE_ITEM_MAX_NUM);
}
// 40250 UserInterface/PythonGuild.cpp // 40250 UserInterface/PythonGuild.cpp
void AddStubConstants_guild(PyObject* poModule) void AddStubConstants_guild(PyObject* poModule)
{ {
@@ -8,7 +8,6 @@
void AddStubConstants_background(PyObject* poModule); void AddStubConstants_background(PyObject* poModule);
void AddStubConstants_event(PyObject* poModule); void AddStubConstants_event(PyObject* poModule);
void AddStubConstants_eventMgr(PyObject* poModule); void AddStubConstants_eventMgr(PyObject* poModule);
void AddStubConstants_exchange(PyObject* poModule);
void AddStubConstants_guild(PyObject* poModule); void AddStubConstants_guild(PyObject* poModule);
void AddStubConstants_ime(PyObject* poModule); void AddStubConstants_ime(PyObject* poModule);
void AddStubConstants_messenger(PyObject* poModule); void AddStubConstants_messenger(PyObject* poModule);
@@ -187,46 +186,6 @@ PyMethodDef methods_eventMgr[] = {
{ "Update", stub_eventMgr_Update, METH_VARARGS }, { "Update", stub_eventMgr_Update, METH_VARARGS },
{ NULL, NULL } { NULL, NULL }
}; };
// 40250 UserInterface/PythonExchangeModule.cpp: exchange export names.
PyObject* stub_exchange_InitTrading(PyObject*, PyObject*) { return stub_call_named("exchange.InitTrading", Py_BuildNone()); }
PyObject* stub_exchange_isTrading(PyObject*, PyObject*) { return stub_call_named("exchange.isTrading", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetElkFromSelf(PyObject*, PyObject*) { return stub_call_named("exchange.GetElkFromSelf", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetElkFromTarget(PyObject*, PyObject*) { return stub_call_named("exchange.GetElkFromTarget", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetItemVnumFromSelf(PyObject*, PyObject*) { return stub_call_named("exchange.GetItemVnumFromSelf", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetItemVnumFromTarget(PyObject*, PyObject*) { return stub_call_named("exchange.GetItemVnumFromTarget", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetItemCountFromSelf(PyObject*, PyObject*) { return stub_call_named("exchange.GetItemCountFromSelf", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetItemCountFromTarget(PyObject*, PyObject*) { return stub_call_named("exchange.GetItemCountFromTarget", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetAcceptFromSelf(PyObject*, PyObject*) { return stub_call_named("exchange.GetAcceptFromSelf", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetAcceptFromTarget(PyObject*, PyObject*) { return stub_call_named("exchange.GetAcceptFromTarget", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetNameFromSelf(PyObject*, PyObject*) { return stub_call_named("exchange.GetNameFromSelf", Py_BuildValue("s", "")); }
PyObject* stub_exchange_GetNameFromTarget(PyObject*, PyObject*) { return stub_call_named("exchange.GetNameFromTarget", Py_BuildValue("s", "")); }
PyObject* stub_exchange_GetItemMetinSocketFromTarget(PyObject*, PyObject*) { return stub_call_named("exchange.GetItemMetinSocketFromTarget", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetItemMetinSocketFromSelf(PyObject*, PyObject*) { return stub_call_named("exchange.GetItemMetinSocketFromSelf", Py_BuildValue("i", 0)); }
PyObject* stub_exchange_GetItemAttributeFromTarget(PyObject*, PyObject*) { return stub_call_named("exchange.GetItemAttributeFromTarget", Py_BuildValue("ii", 0, 0)); }
PyObject* stub_exchange_GetItemAttributeFromSelf(PyObject*, PyObject*) { return stub_call_named("exchange.GetItemAttributeFromSelf", Py_BuildValue("ii", 0, 0)); }
PyObject* stub_exchange_GetElkMode(PyObject*, PyObject*) { return stub_call_named("exchange.GetElkMode", Py_BuildValue("b", 0)); }
PyObject* stub_exchange_SetElkMode(PyObject*, PyObject*) { return stub_call_named("exchange.SetElkMode", Py_BuildNone()); }
PyMethodDef methods_exchange[] = {
{ "InitTrading", stub_exchange_InitTrading, METH_VARARGS },
{ "isTrading", stub_exchange_isTrading, METH_VARARGS },
{ "GetElkFromSelf", stub_exchange_GetElkFromSelf, METH_VARARGS },
{ "GetElkFromTarget", stub_exchange_GetElkFromTarget, METH_VARARGS },
{ "GetItemVnumFromSelf", stub_exchange_GetItemVnumFromSelf, METH_VARARGS },
{ "GetItemVnumFromTarget", stub_exchange_GetItemVnumFromTarget, METH_VARARGS },
{ "GetItemCountFromSelf", stub_exchange_GetItemCountFromSelf, METH_VARARGS },
{ "GetItemCountFromTarget", stub_exchange_GetItemCountFromTarget, METH_VARARGS },
{ "GetAcceptFromSelf", stub_exchange_GetAcceptFromSelf, METH_VARARGS },
{ "GetAcceptFromTarget", stub_exchange_GetAcceptFromTarget, METH_VARARGS },
{ "GetNameFromSelf", stub_exchange_GetNameFromSelf, METH_VARARGS },
{ "GetNameFromTarget", stub_exchange_GetNameFromTarget, METH_VARARGS },
{ "GetItemMetinSocketFromTarget", stub_exchange_GetItemMetinSocketFromTarget, METH_VARARGS },
{ "GetItemMetinSocketFromSelf", stub_exchange_GetItemMetinSocketFromSelf, METH_VARARGS },
{ "GetItemAttributeFromTarget", stub_exchange_GetItemAttributeFromTarget, METH_VARARGS },
{ "GetItemAttributeFromSelf", stub_exchange_GetItemAttributeFromSelf, METH_VARARGS },
{ "GetElkMode", stub_exchange_GetElkMode, METH_VARARGS },
{ "SetElkMode", stub_exchange_SetElkMode, METH_VARARGS },
{ NULL, NULL }
};
// 40250 UserInterface/PythonGuild.cpp: guild export names. // 40250 UserInterface/PythonGuild.cpp: guild export names.
PyObject* stub_guild_IsGuildEnable(PyObject*, PyObject*) { return stub_call_named("guild.IsGuildEnable", Py_BuildValue("i", 0)); } PyObject* stub_guild_IsGuildEnable(PyObject*, PyObject*) { return stub_call_named("guild.IsGuildEnable", Py_BuildValue("i", 0)); }
PyObject* stub_guild_GuildIDToMarkID(PyObject*, PyObject*) { return stub_call_named("guild.GuildIDToMarkID", Py_BuildValue("i", 0)); } PyObject* stub_guild_GuildIDToMarkID(PyObject*, PyObject*) { return stub_call_named("guild.GuildIDToMarkID", Py_BuildValue("i", 0)); }
@@ -798,11 +757,6 @@ void init_2v0_gameplay_stubs() {
PyModule_AddIntConstant(module, "__port_stub__", 1); PyModule_AddIntConstant(module, "__port_stub__", 1);
AddStubConstants_eventMgr(module); AddStubConstants_eventMgr(module);
} }
{
PyObject* module = Py_InitModule("exchange", methods_exchange);
PyModule_AddIntConstant(module, "__port_stub__", 1);
AddStubConstants_exchange(module);
}
{ {
PyObject* module = Py_InitModule("guild", methods_guild); PyObject* module = Py_InitModule("guild", methods_guild);
PyModule_AddIntConstant(module, "__port_stub__", 1); PyModule_AddIntConstant(module, "__port_stub__", 1);
@@ -349,6 +349,7 @@ bool run_main_script_body(const char* lpCmdLine, std::string* error)
initPlayer(); initPlayer();
initItem(); initItem();
initNonPlayer(); initNonPlayer();
initTrade();
initChat(); initChat();
initnet(); initnet();
initeffect(); initeffect();
@@ -1,108 +0,0 @@
// Stand-in for the 40250 logic unit UserInterface/PythonExchange.cpp, not ported yet: the members the ported units
// reference, as platform_stub.py stubs. Delete this file in the commit that ports the unit into port/
// (docs/PORT-PLAN.md).
#include "UserInterface/StdAfx.h"
#include "UserInterface/PythonExchange.h"
#include "../../PlatformStub.h"
CPythonExchange::CPythonExchange()
{
MT_PLATFORM_STUB();
}
CPythonExchange::~CPythonExchange()
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::Clear() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::Start() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::End() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::isTrading() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CPythonExchange::SetSelfName(const char *) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetTargetName(const char *) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetElkToTarget(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetElkToSelf(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetItemToTarget(DWORD, DWORD, BYTE) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetItemToSelf(DWORD, DWORD, BYTE) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetItemMetinSocketToTarget(int, int, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetItemMetinSocketToSelf(int, int, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetItemAttributeToTarget(int, int, BYTE, short) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetItemAttributeToSelf(int, int, BYTE, short) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::DelItemOfTarget(BYTE) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::DelItemOfSelf(BYTE) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetAcceptToTarget(BYTE) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonExchange::SetAcceptToSelf(BYTE) -> void
{
MT_PLATFORM_STUB();
}
@@ -0,0 +1,248 @@
#include "StdAfx.h"
#include "PythonExchange.h"
void CPythonExchange::SetSelfName(const char *name)
{
strncpy(m_self.name, name, CHARACTER_NAME_MAX_LEN);
}
void CPythonExchange::SetTargetName(const char *name)
{
strncpy(m_victim.name, name, CHARACTER_NAME_MAX_LEN);
}
char * CPythonExchange::GetNameFromSelf()
{
return m_self.name;
}
char * CPythonExchange::GetNameFromTarget()
{
return m_victim.name;
}
void CPythonExchange::SetElkToTarget(DWORD elk)
{
m_victim.elk = elk;
}
void CPythonExchange::SetElkToSelf(DWORD elk)
{
m_self.elk = elk;
}
DWORD CPythonExchange::GetElkFromTarget()
{
return m_victim.elk;
}
DWORD CPythonExchange::GetElkFromSelf()
{
return m_self.elk;
}
void CPythonExchange::SetItemToTarget(DWORD pos, DWORD vnum, BYTE count)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
m_victim.item_vnum[pos] = vnum;
m_victim.item_count[pos] = count;
}
void CPythonExchange::SetItemToSelf(DWORD pos, DWORD vnum, BYTE count)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
m_self.item_vnum[pos] = vnum;
m_self.item_count[pos] = count;
}
void CPythonExchange::SetItemMetinSocketToTarget(int pos, int imetinpos, DWORD vnum)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
m_victim.item_metin[pos][imetinpos] = vnum;
}
void CPythonExchange::SetItemMetinSocketToSelf(int pos, int imetinpos, DWORD vnum)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
m_self.item_metin[pos][imetinpos] = vnum;
}
void CPythonExchange::SetItemAttributeToTarget(int pos, int iattrpos, BYTE byType, short sValue)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
m_victim.item_attr[pos][iattrpos].bType = byType;
m_victim.item_attr[pos][iattrpos].sValue = sValue;
}
void CPythonExchange::SetItemAttributeToSelf(int pos, int iattrpos, BYTE byType, short sValue)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
m_self.item_attr[pos][iattrpos].bType = byType;
m_self.item_attr[pos][iattrpos].sValue = sValue;
}
void CPythonExchange::DelItemOfTarget(BYTE pos)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
m_victim.item_vnum[pos] = 0;
m_victim.item_count[pos] = 0;
}
void CPythonExchange::DelItemOfSelf(BYTE pos)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
m_self.item_vnum[pos] = 0;
m_self.item_count[pos] = 0;
}
DWORD CPythonExchange::GetItemVnumFromTarget(BYTE pos)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return 0;
return m_victim.item_vnum[pos];
}
DWORD CPythonExchange::GetItemVnumFromSelf(BYTE pos)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return 0;
return m_self.item_vnum[pos];
}
BYTE CPythonExchange::GetItemCountFromTarget(BYTE pos)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return 0;
return m_victim.item_count[pos];
}
BYTE CPythonExchange::GetItemCountFromSelf(BYTE pos)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return 0;
return m_self.item_count[pos];
}
DWORD CPythonExchange::GetItemMetinSocketFromTarget(BYTE pos, int iMetinSocketPos)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return 0;
return m_victim.item_metin[pos][iMetinSocketPos];
}
DWORD CPythonExchange::GetItemMetinSocketFromSelf(BYTE pos, int iMetinSocketPos)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return 0;
return m_self.item_metin[pos][iMetinSocketPos];
}
void CPythonExchange::GetItemAttributeFromTarget(BYTE pos, int iAttrPos, BYTE * pbyType, short * psValue)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
*pbyType = m_victim.item_attr[pos][iAttrPos].bType;
*psValue = m_victim.item_attr[pos][iAttrPos].sValue;
}
void CPythonExchange::GetItemAttributeFromSelf(BYTE pos, int iAttrPos, BYTE * pbyType, short * psValue)
{
if (pos >= EXCHANGE_ITEM_MAX_NUM)
return;
*pbyType = m_self.item_attr[pos][iAttrPos].bType;
*psValue = m_self.item_attr[pos][iAttrPos].sValue;
}
void CPythonExchange::SetAcceptToTarget(BYTE Accept)
{
m_victim.accept = Accept ? true : false;
}
void CPythonExchange::SetAcceptToSelf(BYTE Accept)
{
m_self.accept = Accept ? true : false;
}
bool CPythonExchange::GetAcceptFromTarget()
{
return m_victim.accept ? true : false;
}
bool CPythonExchange::GetAcceptFromSelf()
{
return m_self.accept ? true : false;
}
bool CPythonExchange::GetElkMode()
{
return m_elk_mode;
}
void CPythonExchange::SetElkMode(bool value)
{
m_elk_mode = value;
}
void CPythonExchange::Start()
{
m_isTrading = true;
}
void CPythonExchange::End()
{
m_isTrading = false;
}
bool CPythonExchange::isTrading()
{
return m_isTrading;
}
void CPythonExchange::Clear()
{
memset(&m_self, 0, sizeof(m_self));
memset(&m_victim, 0, sizeof(m_victim));
/*
m_self.item_vnum[0] = 30;
m_victim.item_vnum[0] = 30;
m_victim.item_vnum[1] = 40;
m_victim.item_vnum[2] = 50;
*/
}
CPythonExchange::CPythonExchange()
{
Clear();
m_isTrading = false;
m_elk_mode = false;
// Clear로 옴겨놓으면 안됨.
// trade_start 페킷이 오면 Clear를 실행하는데
// m_elk_mode는 클리어 되선 안됨.;
}
CPythonExchange::~CPythonExchange()
{
}
@@ -0,0 +1,191 @@
#include "StdAfx.h"
#include "PythonExchange.h"
PyObject * exchangeInitTrading(PyObject * poSelf, PyObject * poArgs)
{
CPythonExchange::Instance().End();
return Py_BuildNone();
}
PyObject * exchangeisTrading(PyObject * poSelf, PyObject * poArgs)
{
return Py_BuildValue("i", CPythonExchange::Instance().isTrading());
}
PyObject * exchangeGetElkFromSelf(PyObject * poSelf, PyObject * poArgs)
{
return Py_BuildValue("i", CPythonExchange::Instance().GetElkFromSelf());
}
PyObject * exchangeGetElkFromTarget(PyObject * poSelf, PyObject * poArgs)
{
return Py_BuildValue("i", CPythonExchange::Instance().GetElkFromTarget());
}
PyObject * exchangeGetAcceptFromSelf(PyObject * poSelf, PyObject * poArgs)
{
return Py_BuildValue("i", CPythonExchange::Instance().GetAcceptFromSelf());
}
PyObject * exchangeGetAcceptFromTarget(PyObject * poSelf, PyObject * poArgs)
{
return Py_BuildValue("i", CPythonExchange::Instance().GetAcceptFromTarget());
}
PyObject * exchangeGetItemVnumFromSelf(PyObject * poSelf, PyObject * poArgs)
{
int pos;
if (!PyTuple_GetInteger(poArgs, 0, &pos))
return Py_BuildException();
return Py_BuildValue("i", CPythonExchange::Instance().GetItemVnumFromSelf((char) pos));
}
PyObject * exchangeGetItemVnumFromTarget(PyObject * poTarget, PyObject * poArgs)
{
int pos;
if (!PyTuple_GetInteger(poArgs, 0, &pos))
return Py_BuildException();
return Py_BuildValue("i", CPythonExchange::Instance().GetItemVnumFromTarget((char) pos));
}
PyObject * exchangeGetItemCountFromSelf(PyObject * poSelf, PyObject * poArgs)
{
int pos;
if (!PyTuple_GetInteger(poArgs, 0, &pos))
return Py_BuildException();
return Py_BuildValue("i", CPythonExchange::Instance().GetItemCountFromSelf((char) pos));
}
PyObject * exchangeGetItemCountFromTarget(PyObject * poTarget, PyObject * poArgs)
{
int pos;
if (!PyTuple_GetInteger(poArgs, 0, &pos))
return Py_BuildException();
return Py_BuildValue("i", CPythonExchange::Instance().GetItemCountFromTarget((char) pos));
}
PyObject * exchangeGetNameFromSelf(PyObject * poTarget, PyObject * poArgs)
{
return Py_BuildValue("s", CPythonExchange::Instance().GetNameFromSelf());
}
PyObject * exchangeGetNameFromTarget(PyObject * poTarget, PyObject * poArgs)
{
return Py_BuildValue("s", CPythonExchange::Instance().GetNameFromTarget());
}
PyObject * exchangeGetItemMetinSocketFromTarget(PyObject * poTarget, PyObject * poArgs)
{
int pos;
if (!PyTuple_GetInteger(poArgs, 0, &pos))
return Py_BuildException();
int iMetinSocketPos;
if (!PyTuple_GetInteger(poArgs, 1, &iMetinSocketPos))
return Py_BuildException();
return Py_BuildValue("i", CPythonExchange::Instance().GetItemMetinSocketFromTarget(pos, iMetinSocketPos));
}
PyObject * exchangeGetItemMetinSocketFromSelf(PyObject * poTarget, PyObject * poArgs)
{
int pos;
if (!PyTuple_GetInteger(poArgs, 0, &pos))
return Py_BuildException();
int iMetinSocketPos;
if (!PyTuple_GetInteger(poArgs, 1, &iMetinSocketPos))
return Py_BuildException();
return Py_BuildValue("i", CPythonExchange::Instance().GetItemMetinSocketFromSelf(pos, iMetinSocketPos));
}
PyObject * exchangeGetItemAttributeFromTarget(PyObject * poTarget, PyObject * poArgs)
{
int pos;
if (!PyTuple_GetInteger(poArgs, 0, &pos))
return Py_BuildException();
int iAttrSlotPos;
if (!PyTuple_GetInteger(poArgs, 1, &iAttrSlotPos))
return Py_BuildException();
BYTE byType;
short sValue;
CPythonExchange::Instance().GetItemAttributeFromTarget(pos, iAttrSlotPos, &byType, &sValue);
return Py_BuildValue("ii", byType, sValue);
}
PyObject * exchangeGetItemAttributeFromSelf(PyObject * poTarget, PyObject * poArgs)
{
int pos;
if (!PyTuple_GetInteger(poArgs, 0, &pos))
return Py_BuildException();
int iAttrSlotPos;
if (!PyTuple_GetInteger(poArgs, 1, &iAttrSlotPos))
return Py_BuildException();
BYTE byType;
short sValue;
CPythonExchange::Instance().GetItemAttributeFromSelf(pos, iAttrSlotPos, &byType, &sValue);
return Py_BuildValue("ii", byType, sValue);
}
PyObject * exchangeGetElkMode(PyObject * poTarget, PyObject * poArgs)
{
return Py_BuildValue("b", CPythonExchange::Instance().GetElkMode());
}
PyObject * exchangeSetElkMode(PyObject * poTarget, PyObject * poArgs)
{
int elk_mode;
if (!PyTuple_GetInteger(poArgs, 0, &elk_mode))
return Py_BuildException();
CPythonExchange::Instance().SetElkMode(elk_mode ? true : false);
return Py_BuildNone();
}
void initTrade()
{
static PyMethodDef s_methods[] =
{
{"InitTrading", exchangeInitTrading, METH_VARARGS},
{"isTrading", exchangeisTrading, METH_VARARGS},
{"GetElkFromSelf", exchangeGetElkFromSelf, METH_VARARGS},
{"GetElkFromTarget", exchangeGetElkFromTarget, METH_VARARGS},
{"GetItemVnumFromSelf", exchangeGetItemVnumFromSelf, METH_VARARGS},
{"GetItemVnumFromTarget", exchangeGetItemVnumFromTarget, METH_VARARGS},
{"GetItemCountFromSelf", exchangeGetItemCountFromSelf, METH_VARARGS},
{"GetItemCountFromTarget", exchangeGetItemCountFromTarget, METH_VARARGS},
{"GetAcceptFromSelf", exchangeGetAcceptFromSelf, METH_VARARGS},
{"GetAcceptFromTarget", exchangeGetAcceptFromTarget, METH_VARARGS},
{"GetNameFromSelf", exchangeGetNameFromSelf, METH_VARARGS},
{"GetNameFromTarget", exchangeGetNameFromTarget, METH_VARARGS},
{"GetItemMetinSocketFromTarget", exchangeGetItemMetinSocketFromTarget, METH_VARARGS},
{"GetItemMetinSocketFromSelf", exchangeGetItemMetinSocketFromSelf, METH_VARARGS},
{"GetItemAttributeFromTarget", exchangeGetItemAttributeFromTarget, METH_VARARGS},
{"GetItemAttributeFromSelf", exchangeGetItemAttributeFromSelf, METH_VARARGS},
{"GetElkMode", exchangeGetElkMode, METH_VARARGS},
{"SetElkMode", exchangeSetElkMode, METH_VARARGS},
{NULL, NULL},
};
PyObject * poModule = Py_InitModule("exchange", s_methods);
PyModule_AddIntConstant(poModule, "EXCHANGE_ITEM_MAX_NUM", CPythonExchange::EXCHANGE_ITEM_MAX_NUM);
}
@@ -49,6 +49,7 @@ void initchrmgr();
void initPlayer(); void initPlayer();
void initItem(); void initItem();
void initNonPlayer(); void initNonPlayer();
void initTrade();
void initChat(); void initChat();
void initnet(); void initnet();
void initeffect(); void initeffect();
@@ -616,6 +616,45 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
if (pickup.vid == kGroundItemVID && !c.Send(del)) if (pickup.vid == kGroundItemVID && !c.Send(del))
return Fail(name + ": send GC_ITEM_GROUND_DEL"); return Fail(name + ": send GC_ITEM_GROUND_DEL");
} }
// CInputMain::Exchange (input_main.cpp) → CHARACTER::ExchangeStart / CExchange::Cancel: the partner is
// played by the server itself — START names the requested vid, then the partner's item (vnum 19, cell 0)
// and gold arrive the way CExchange::AddItem/AddGold send them with is_me=false; CANCEL answers END.
if (header == HDR_CG_EXCHANGE)
{
CGExchange ex;
std::memcpy(&ex, packet, sizeof(ex));
// arg1 only means something for START (40250 SendExchangeExitPacket leaves it uninitialised).
Event(name + ":exchange " + std::to_string(ex.subheader) +
(ex.subheader == EXCHANGE_CG_START ? " " + std::to_string(ex.arg1) : std::string()));
GCExchange out = zeroed<GCExchange>();
out.header = HDR_GC_EXCHANGE;
out.arg2 = {0xff, 0xffff}; // NPOS
bool ok = true;
if (ex.subheader == EXCHANGE_CG_START)
{
out.subheader = EXCHANGE_GC_START;
out.arg1 = ex.arg1;
ok = c.Send(out);
out.subheader = EXCHANGE_GC_ITEM_ADD;
out.arg1 = kExchangeItemVnum;
out.arg2 = {1, 0}; // INVENTORY, cell 0
out.arg3 = 1;
ok = ok && c.Send(out);
out = zeroed<GCExchange>();
out.header = HDR_GC_EXCHANGE;
out.subheader = EXCHANGE_GC_GOLD_ADD;
out.arg2 = {0xff, 0xffff};
out.arg1 = kExchangeGold;
ok = ok && c.Send(out);
}
else if (ex.subheader == EXCHANGE_CG_CANCEL)
{
out.subheader = EXCHANGE_GC_END;
ok = c.Send(out);
}
if (!ok)
return Fail(name + ": send GC_EXCHANGE");
}
if (header == HDR_CG_MOVE) if (header == HDR_CG_MOVE)
{ {
CGMove move; CGMove move;
+1
View File
@@ -25,6 +25,7 @@ public:
static constexpr std::uint32_t kGroundItemVID = 0x00054321; static constexpr std::uint32_t kGroundItemVID = 0x00054321;
static constexpr std::uint32_t kGroundItemVnum = 19; static constexpr std::uint32_t kGroundItemVnum = 19;
static constexpr std::int32_t kGroundItemX = kX + 150, kGroundItemY = kY; static constexpr std::int32_t kGroundItemX = kX + 150, kGroundItemY = kY;
static constexpr std::uint32_t kExchangeItemVnum = 19, kExchangeGold = 1000;
~FakeLoginServer(); ~FakeLoginServer();
+23 -1
View File
@@ -50,6 +50,7 @@
#include "GameLib/ItemManager.h" #include "GameLib/ItemManager.h"
#include "UserInterface/PythonItem.h" #include "UserInterface/PythonItem.h"
#include "UserInterface/StdAfx.h" #include "UserInterface/StdAfx.h"
#include "UserInterface/PythonExchange.h"
#include "UserInterface/PythonCharacterManager.h" #include "UserInterface/PythonCharacterManager.h"
#include "UserInterface/InstanceBase.h" #include "UserInterface/InstanceBase.h"
#include "UserInterface/PythonBackground.h" #include "UserInterface/PythonBackground.h"
@@ -518,6 +519,26 @@ int main(int argc, char** argv)
CHECK(pump_until(2, [&] { return !ground.GetGroundItemPosition(FakeLoginServer::kGroundItemVID, &item_pos); })); CHECK(pump_until(2, [&] { return !ground.GetGroundItemPosition(FakeLoginServer::kGroundItemVID, &item_pos); }));
} }
// Exchange (CPythonExchange + exchange module): net.SendExchangeStartPacket → the fake partner's GC_EXCHANGE
// START/ITEM_ADD/GOLD_ADD fill the target side and open uiexchange; net.SendExchangeExitPacket → END.
if (server)
{
CHECK(py("import net\nnet.SendExchangeStartPacket(" + std::to_string(FakeLoginServer::kMainVID) + ")"));
CHECK(pump_until(2, [&] { return CPythonExchange::Instance().GetElkFromTarget() == FakeLoginServer::kExchangeGold; }));
CHECK(py("import exchange\n"
"assert exchange.isTrading() == 1\n"
"assert exchange.GetItemVnumFromTarget(0) == " + std::to_string(FakeLoginServer::kExchangeItemVnum) + "\n"
"assert exchange.GetItemCountFromTarget(0) == 1\n"
"assert exchange.GetElkFromSelf() == 0"));
CHECK(py("import net\nnet.SendExchangeExitPacket()"));
CHECK(pump_until(2, [&] { return !CPythonExchange::Instance().isTrading(); }));
CHECK(server->Has("game2:exchange 0 " + std::to_string(FakeLoginServer::kMainVID)));
CHECK(server->Has("game2:exchange 5"));
// uiexchange.CloseDialog armed wndMgr.OnceIgnoreMouseLeftButtonUpEvent (in the client that release belongs
// to the click that closed the dialog); spend it so step 8's click-release is not swallowed.
PythonBoot::UIMouseButton(1, false, 400, 520);
}
// 8. (批次 2V3) Click-to-move: a left click on the ground below the actor reaches game.GameWindow's // 8. (批次 2V3) Click-to-move: a left click on the ground below the actor reaches game.GameWindow's
// OnMouseLeftButtonDown → player.SetMouseState(MBT_LEFT, MBS_PRESS); CPythonPlayer picks the ground // OnMouseLeftButtonDown → player.SetMouseState(MBT_LEFT, MBS_PRESS); CPythonPlayer picks the ground
// through the cursor ray (CScreen::SetCursorPosition → CPythonBackground::GetPickingPoint) and the // through the cursor ray (CScreen::SetCursorPosition → CPythonBackground::GetPickingPoint) and the
@@ -565,7 +586,8 @@ int main(int argc, char** argv)
want.push_back(e); want.push_back(e);
for (const auto& e : events) for (const auto& e : events)
if (e.rfind(prefix, 0) == 0 && e.find(":move ") == std::string::npos && if (e.rfind(prefix, 0) == 0 && e.find(":move ") == std::string::npos &&
e.find(":pickup ") == std::string::npos) e.find(":pickup ") == std::string::npos &&
e.find(":exchange ") == std::string::npos)
got.push_back(e); got.push_back(e);
CHECK(want == got); CHECK(want == got);
} }