|
|
 | |  |  | WARN - 找不到指定的材料 ObjId (main=0, aid=0)
關於您在「[版本] 815登入器+主程式+核心源碼_整理過的」的帖子
yasioukon大大 我卡住了
package com.lineage.server.serverpackets;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.model.Instance.L1NpcInstance;
import java.util.List;
import java.util.ArrayList;
public class S_ItemSmelt extends ServerBasePacket {
private static final Log _log = LogFactory.getLog(S_ItemSmelt.class);
public S_ItemSmelt(L1NpcInstance npc) {
try {
// Opcode: 熔煉 UI
writeC(OpcodesServer.S_VOICE_CHAT); // 156
writeC(48); // 熔煉 UI type
writeD(npc.getId()); // NPC ObjectId
} catch (Exception e) {
_log.error(e.getLocalizedMessage(), e);
}
}
public S_ItemSmelt(L1NpcInstance npc, List<Integer> mainMaterials, List<Integer> aidMaterials, int resultItemId, int successRate) {
try {
// 打開熔煉 UI
writeC(OpcodesServer.S_VOICE_CHAT); // 156
writeC(48); // 熔煉 UI type
writeD(npc.getId()); // NPC ObjectId
// 主材料清單
writeC(mainMaterials.size());
for (int itemId : mainMaterials) {
writeD(itemId);
}
// 輔助材料清單
writeC(aidMaterials.size());
for (int itemId : aidMaterials) {
writeD(itemId);
}
// 熔煉結果
writeD(resultItemId); // 火神結晶 itemId
writeC(successRate); // 成功率 (例如 80%)
} catch (Exception e) {
_log.error("S_ItemSmelt error: " + e.getMessage(), e);
}
}
// /**
// * 熔煉結果封包
// * @param isSuccess 熔煉是否成功
// * @param resultItems 熔煉後給予的物品清單
// */
// public S_ItemSmelt(final boolean isSuccess, final List<L1ItemInstance> giveItemObjs) {
// try {
// writeC(S_EXTENDED_PROTOBUF);
// writeC(59);
// a(8, isSuccess ? 0L : 1L);
// if (giveItemObjs != null) {
// for (final L1ItemInstance itemObj : giveItemObjs) {
// a(18, new S_CraftContent().jdMethod_if(itemObj));
// }
// }
// writeC(3);
// writeC(116);
//
// } catch (final Exception e) {
// _log.error(e.getLocalizedMessage(), e);
// }
// }
@Override
public byte[] getContent() {
return _bao.toByteArray();
}
@Override
public String getType() {
return this.getClass().getSimpleName();
}
}
-------------------------------
package com.lineage.server.clientpackets;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.lineage.echo.ClientExecutor;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.datatables.ItemTable;
import com.lineage.server.serverpackets.S_ItemSmeltResult;
/**
* 熔煉確認封包 (Opcode=250)
* 玩家在熔煉 UI 按下「確認」時送出
*/
public class C_ItemSmelt extends ClientBasePacket {
private static final Log _log = LogFactory.getLog(C_ItemSmelt.class);
private static final Random random = new Random();
// 熔煉成功率 (可調整)
private static final int SUCCESS_RATE = 80;
@Override
public void start(byte[] decrypt, ClientExecutor client) throws Exception {
try {
read(decrypt);
L1PcInstance pc = client.getActiveChar();
if (pc == null) {
return;
}
int reservedH = readH(); // 保留 short
int reservedD = readD(); // 保留 int
int msgId = readH(); // 封包訊息 ID
int mainObjId = readD(); // 主材料 ObjId
int aidObjId = readD(); // 輔助材料 ObjId
_log.debug(String.format(
"Smelt Packet解析: reservedH=%d, reservedD=%d, msgId=%d, mainObjId=%d, aidObjId=%d",
reservedH, reservedD, msgId, mainObjId, aidObjId
));
// 用 ObjId 查找背包物品
L1ItemInstance mainItem = pc.getInventory().getItem(mainObjId);
L1ItemInstance aidItem = pc.getInventory().getItem(aidObjId);
boolean success = false;
L1ItemInstance resultItem = null;
if (mainItem == null || aidItem == null) {
_log.warn("找不到指定的材料 ObjId (main=" + mainObjId + ", aid=" + aidObjId + ")");
pc.sendPackets(new S_ItemSmeltResult(false, new ArrayList<>()));
return;
}
_log.info("主材料存在: ObjId=" + mainItem.getId() + ", itemId=" + mainItem.getItemId());
_log.info("輔助材料存在: ObjId=" + aidItem.getId() + ", itemId=" + aidItem.getItemId());
// 驗證配方
if ((mainItem.getItemId() == 200041 || mainItem.getItemId() == 100037 || mainItem.getItemId() == 200052) &&
(aidItem.getItemId() == 80027 || aidItem.getItemId() == 80028 || aidItem.getItemId() == 80322)) {
// 消耗材料
pc.getInventory().removeItem(mainItem, 1);
pc.getInventory().removeItem(aidItem, 1);
// 成功率判斷
success = random.nextInt(100) < SUCCESS_RATE;
if (success) {
resultItem = ItemTable.get().createItem(80029); // 火神結晶
resultItem.setCount(1);
pc.getInventory().storeItem(resultItem);
_log.info("熔煉成功,生成火神結晶 itemId=80029");
} else {
_log.info("熔煉失敗,沒有生成結晶");
}
} else {
_log.warn("材料不符合熔煉配方");
}
List<L1ItemInstance> results = new ArrayList<>();
if (resultItem != null) {
results.add(resultItem);
}
pc.sendPackets(new S_ItemSmeltResult(success, results));
_log.info("Send SmeltResult with subId=61, success=" + success);
} catch (Exception e) {
_log.error("C_ItemSmelt error: " + e.getMessage(), e);
} finally {
over();
}
}
}
-------------------------------------
package com.lineage.server.serverpackets;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.lineage.server.model.Instance.L1ItemInstance;
/**
* 熔煉結果封包
* 成功/失敗 + 結果物品清單
*/
public class S_ItemSmeltResult extends ServerBasePacket {
private static final Log _log = LogFactory.getLog(S_ItemSmeltResult.class);
private static final String TYPE = "[S] S_ItemSmeltResult";
public S_ItemSmeltResult(boolean isSuccess, List<L1ItemInstance> resultItems) {
try {
_log.info("SmeltResult: success=" + isSuccess);
if (resultItems != null) {
for (L1ItemInstance item : resultItems) {
_log.info("ResultItem: id=" + item.getItemId() + ", count=" + item.getCount());
}
}
// 封包結構
writeC(OpcodesServer.S_EXTENDED_PROTOBUF); // 主 opcode
writeH(61); // 子編號 (熔煉結果)
writeH(0); // 保留
_log.info("Send SmeltResult with subId=61, success=" + isSuccess);
// 成功/失敗 flag
writeC(isSuccess ? 1 : 0);
// 結果物品清單
if (resultItems != null && !resultItems.isEmpty()) {
writeC(resultItems.size()); // 結果數量
for (L1ItemInstance item : resultItems) {
writeD((int) item.getItemId()); // ★ 強制轉型成 int
writeD((int) item.getCount()); // ★ 強制轉型成 int
}
} else {
writeC(0); // 沒有結果
}
} catch (Exception e) {
_log.error("S_ItemSmeltResult error: " + e.getMessage(), e);
}
}
@Override
public byte[] getContent() {
return getBytes();
}
@Override
public String getType() {
return TYPE;
}
}
----------------------------------
package com.lineage.data.npc;
import com.lineage.data.executor.NpcExecutor;
import com.lineage.server.datatables.T_CraftConfigTable;
import com.lineage.server.model.Broadcaster;
import com.lineage.server.model.Instance.L1NpcInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.serverpackets.S_ChangeHeading;
import com.lineage.server.serverpackets.S_NPCTalkReturn;
import com.lineage.server.serverpackets.S_NpcChatPacket;
import com.lineage.server.thread.GeneralThreadPool;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.lineage.server.serverpackets.S_ItemCraftList;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.serverpackets.S_ItemSmelt;
import com.lineage.server.serverpackets.S_ItemSmeltResult;
import java.util.List;
import java.util.ArrayList;
import com.lineage.server.model.L1ObjectAmount;
import com.lineage.server.datatables.ItemTable;
import java.util.Arrays;
/**
* 火神學徒 NPC 腳本
*/
public class L1NpcFireSmith1 extends NpcExecutor {
private static final Log _log = LogFactory.getLog(L1NpcFireSmith1.class);
// 供 NpcTable 反射呼叫
public static NpcExecutor get() {
return new L1NpcFireSmith1();
}
/**
* 每 15 秒觸發一次工作邏輯
*/
@Override
public int workTime() {
return 15;
}
@Override
public void talk(final L1PcInstance pc, final L1NpcInstance npc) {
// npc.setHeading(pc.getHeading());
// Broadcaster.broadcastPacket(npc, new S_ChangeHeading(npc));
// int oid = npc.getId(); // 取得 NPC ObjectId
// _log.info("NPC ObjectId = " + oid + ", NpcId = " + npc.getNpcId());
pc.sendPackets(new S_NPCTalkReturn(pc.getId(), "a_firesmith1"));
}
@Override
public void action(final L1PcInstance pc, final L1NpcInstance npc, final String cmd, final long amount) {
npc.setHeading(pc.getHeading());
Broadcaster.broadcastPacket(npc, new S_ChangeHeading(npc));
try {
if (cmd.equalsIgnoreCase("openSmelt")) {
// 主材料:武士刀、大馬士革刀、雙手劍
List<Integer> mains = Arrays.asList(200041, 100037, 200052);
// 輔助材料:火神之槌、火神契約、火神痕跡
List<Integer> aids = Arrays.asList(80027, 80028, 80322);
// 熔煉結果:火神結晶 (itemId=80029),成功率 80%
int resultItemId = 80029;
int successRate = 80;
pc.sendPackets(new S_ItemSmelt(npc, mains, aids, resultItemId, successRate));
_log.info("NPCAction: 打開熔煉 UI (openSmelt)");
return;
}
// ⚠️ 熔煉執行不是靠 cmd,而是靠 C_ItemSmelt 封包 (Opcode 250)
// 在 C_ItemSmelt 裡讀取主材料 objid + 輔助材料 objid,驗證並生成結果
// 然後回傳 S_ItemSmeltResult 封包給客戶端
_log.debug("NPCAction: 未知指令 cmd=" + cmd);
} catch (Exception e) {
_log.error("Craft/Smelt packet error: " + e.getMessage(), e);
}
}
// @Override
// public void action(final L1PcInstance pc, final L1NpcInstance npc, final String cmd, final long amount) {
// npc.setHeading(pc.getHeading());
// Broadcaster.broadcastPacket(npc, new S_ChangeHeading(npc));
// try {
//
//
// if (cmd.equalsIgnoreCase("openCrystal")) {
// _log.error("MakeCrystal_Window");
// pc.sendPackets(new S_ItemSmelt(npc));
// return;
// }
//
//
// // 直接用 cmd 當 Action Name 去查
// List<T_CraftConfigTable.NewL1NpcMakeItemAction> actions =
// T_CraftConfigTable.get().getNpcMakeItemActionList(npc.getNpcId(), cmd);
//
// if (actions != null && !actions.isEmpty()) {
// for (T_CraftConfigTable.NewL1NpcMakeItemAction action : actions) {
// pc.sendPackets(action.getPacket());
// }
// } else {
// pc.sendPackets(new S_NPCTalkReturn(pc.getId(), "smithitem3"));
// }
//
// } catch (Exception e) {
// _log.error("Craft packet error: " + e.getMessage(), e);
// pc.sendPackets(new S_NPCTalkReturn(pc.getId(), "smithitem3"));
// }
// }
@Override
public void spawn(final L1NpcInstance npc) {
Broadcaster.broadcastPacket(npc,
new S_NpcChatPacket(npc, "\\fH火神學徒出現了!快來吧!", 2));
System.out.println("[DEBUG] spawn() 被呼叫, npcId=" + npc.getNpcId());
// 設定 600 分鐘後自動消失
GeneralThreadPool.get().schedule(() -> {
npc.deleteMe();
}, 3 * 60 * 1000);
}
// @Override
// public int type() { return 32 + 4 + 8 + 16 + 2; } // spawn + attack + death + work
@Override
public int type() {
// 這裡回傳 NPC 類型代號,對應 NpcExecutor 的 bitmask
// 2 = NPC 對話執行
return 2;
}
}
--------------------------------
結果
【Client → Server】
[C opcode] = 142 [Length] = 16
0000: 8e 61 1b 36 77 6f 70 65 6e 53 6d 65 6c 74 00 00 .a.6wopenSmelt..
→ Opcode = 142
→ 保留 H = 7009
→ 保留 D = 1886353206
→ msgId = 21358
INFO - NPCAction 收到指令: openSmelt
INFO - NPCAction: 打開熔煉 UI (openSmelt)
【Client → Server】
[C opcode] = 250 [Length] = 16
0000: fa 0d 61 1b 36 77 18 05 11 00 24 05 11 00 a0 c9 ..a.6w....$.....
→ Opcode = 250
→ 保留 H = 24845
→ 保留 D = 410465819
→ msgId = 17
DEBUG - Smelt Packet解析: npcObjId=907763981, reservedH=6263, reservedD=603984133, msgId=4357, mainObjId=0, aidObjId=0
WARN - 找不到指定的材料 ObjId (main=0, aid=0)
INFO - SmeltResult: success=false
INFO - Send SmeltResult with subId=61, success=false
---------------------------------
我把道具拖到 榮煉介面之後 有顯示圖案 但是 道具欄沒有扣
只是圖案放上去而已 沒有真正 成功
有沒有大大知道怎麼解決 請大大們 幫幫忙
| |  | |  |
|
上一篇︰ 5/30更新 3.8 登入器(天M天R編碼順跑帶自動練功系統)下一篇︰ 請問有大大知道是缺什麼圖嗎
|