在開發好友系統時, 做了個功能叫做推薦名單, 也就是將最近對戰的玩家記錄到數據表上, 再推給客戶端, 但在獲取數據時發現必須過濾掉已經添加的清單, 索性在表格上添加了一個字段來紀錄是否有效
45883-4ngtcpyj76m.png

後來發現Chloe處理這段很麻煩, 沒查到官方有 replace 的功能, 所以自己用了 procedure 來處理, 有點久沒用研究了下 Chole 怎麼調用

官方文檔說明
https://github.com/shuxinqin/Chloe/wiki/Oracle-procedure
42712-uac01obubl8.png

兩個寫法不一樣, dbContext.SqlQuery 是直接獲取 Procedure 返回數據的, 就譬如 procedure 最後面寫了 select * from user limit 1; 可以透過這個方式獲取返回的 user 資料, 而 ExecuteNonQuery("Proc_GetPersonName", CommandType.StoredProcedure, id, outputName) 則是透過 Procedure 的 out 獲取數據

我們在更新 recent 表格同時也要獲取 recent 數據, 作法如果

DbParam iUserId = new DbParam("@iUserId", userId);
DbParam iRUserId = new DbParam("@iRUserId", recentUserId);
DbParam iState = new DbParam("@iState", 1);
dbContext.SqlQuery<Tbl_Recent>("proc_update_recent", CommandType.StoredProcedure, iUserId, iRUserId, iState);

這是一個沒有 return 的 procedure 調用方式, Procedure 如下

CREATE DEFINER=`root`@`127.0.0.1` PROCEDURE `proc_update_recent`(
    IN `iUserId` int,
    IN `iRUserId` int, 
    IN `iState` int)
BEGIN
    DECLARE ts long;
    set ts = (UNIX_TIMESTAMP() * 1000) + (MICROSECOND(NOW(3)) / 1000);

    REPLACE into `recent`(`UserId` ,`RUserId`, `State`)
        value
    (iUserId, iRUserId, iState);
END

另外得益於使用 Procedure , 在發送邀請功能上需要判斷很多情況, 如果在 c# 處理邏輯就會很繁瑣, 後來使用 Procedure 解決, 如下

CREATE DEFINER=`root`@`127.0.0.1` PROCEDURE `proc_check_send_friendApply`(
    IN `iApplyUserId` BIGINT,
    IN `iApplyUserName` VARCHAR(64),
    IN `iApplyUserHead` VARCHAR(128),
    IN `iToUserId` BIGINT, OUT `oData` INT)
MAINLOOP:BEGIN

    # declare timestamp
    DECLARE ts BIGINT(20) default 0;
    DECLARE isMyFriend TINYINT(4) default 0;
    DECLARE findRecent TINYINT(4) default 0;
    DECLARE findFriend TINYINT(4) default 0;
    DECLARE findApply TINYINT(4) default 0;


    set ts = (UNIX_TIMESTAMP() * 1000) + (MICROSECOND(NOW(3)) / 1000);

    #已經是我的好友, 退出流程
    select count(*) into isMyFriend from `friend` where `UserId`=iApplyUserId and `FUserId`=iToUserId;
    if isMyFriend != 0 then
        LEAVE MAINLOOP;
    end if;

    #if 如果Recent裡面有數據, 就改掉 state = 1
    select count(*) into findRecent from `recent` where `UserId`=iApplyUserId and `RUserId`=iToUserId;
    if findRecent != 0 then
        REPLACE into `recent`(`UserId` ,`RUserId`,`State`) value (iApplyUserId, iToUserId, 1);
    end IF;

    #if 對方已經是好友就直接加回去, 
    select count(*) into findFriend from `friend` where `UserId`=iToUserId and `FUserId`=iApplyUserId;
    if findFriend != 0 then
        REPLACE into `friend`(`UserId` ,`FUserId`,`CreateTime`, `UpdateTime`) value (iApplyUserId, iToUserId, ts, ts);
        set oData = 2;
        LEAVE MAINLOOP;
    end if;

    #如果沒有邀請過就發邀請
    select count(*) into findApply from `friendapply` where `ApplyUserId`=iApplyUserId and `ToUserId`=iToUserId;
    if findApply = 0 then
        REPLACE into `friendapply`(`ApplyUserId` ,`ApplyUserName`, `ApplyUserHead`, `ToUserId`, `State`, `CreateTime`, `UpdateTime`)
        value
        (iApplyUserId, iApplyUserName, iApplyUserHead, iToUserId, 0, ts, 0);

        select * from `friendapply` where `ApplyUserId`=iApplyUserId and `ToUserId`=iToUserId limit 1;
        set oData = 1;
    end if;
END

很久以前在做第一版的麻將時發現那位服務端非常喜歡用存儲過程, 可能是因為服務端 nodejs 且沒有做數據持久化的緣故, 很多數據無法獲取必須重新拉數據, 這樣就會造成數據庫壓力很大, 最早接手開發RPG遊戲時必然是必須做數據持久化的, 設計到服務端乘載人數跟架構, 不做數據持久化管理壓力會壓在Mysql上, 後來做博奕遊戲就很少做這塊了, 輕便為主

57 次阅读 阅读全文

AssetStudioGUI 可以用來查看 Unity 包體內容, 可以多看看其他優質產品的資源內容怎麼做的

首先開啟 AssetStudioGUI
56533-xssdnwijam8.png

將 unity 的包給解壓, 用來測試的是之前上傳 Google Play 的 RummyGo aab包
81185-kb3z490tbzb.png

AssetStudioGUI 點擊 文件->加載目錄, 選擇解壓目錄
85830-fao0kd2llnj.png

切換到資源列表, 並點類型排序
96427-dr0n1ygrhel.png

可以直接查看包體內容
42052-yy9rtnr5hs.png

42 次阅读 阅读全文

打包app執行轟炸超人發現遊戲開局就crash了....
43263-pqdof30pwk9.png
95688-6lpou38yl0i.png

在pc上複查發現這個錯誤
04236-o2zub6agc9j.png

最後發現是這邊出錯, int[,]在查詢數據時 address 不知道為什麼出錯了

for (int j = 0; j < map.MapConfig.ChunkH; j++){
    strm += "[";
    for (int i = 0; i < map.MapConfig.ChunkW; i++){
                //這邊出錯
        strm += matrixData[j, i] + ",";
    }
    strm += "],";
}
strm += "]";

詳細錯誤如下

IL_00af: call System.Int32& System.Int32[0...,0...]::Address(System.Int32,System.Int32)
at ETHotfix.AIPlayer.calcNonPath(System.Int32 depth) (at G:/OlgCase/bbm/source/Unity/Assets/Hotfix/GameGather/Bomber/AI/AIPlayer.cs:366)
at ETHotfix.AIPlayer.calcPath() (at G:/OlgCase/bbm/source/Unity/Assets/Hotfix/GameGather/Bomber/AI/AIPlayer.cs:200)
at ETHotfix.AIPlayer.V_Think() (at G:/OlgCase/bbm/source/Unity/Assets/Hotfix/GameGather/Bomber/AI/AIPlayer.cs:86)
at ETHotfix.AIPlayer.think() (at G:/OlgCase/bbm/source/Unity/Assets/Hotfix/GameGather/Bomber/AI/AIPlayer.cs:79)
at ETHotfix.AILogic.UpdateLogic() (at G:/OlgCase/bbm/source/Unity/Assets/Hotfix/GameGather/Bomber/AI/AILogic.cs:292)
at ETHotfix.BaseEntity.updateAILogicAct() (at G:/OlgCase/bbm/source/Unity/Assets/Hotfix/GameGather/Bomber/Entity/BaseEntity.cs:1581)

代碼修改, 把查詢給int再使用就好了

for (int j = 0; j < map.MapConfig.ChunkH; j++){
    strm += "[";
    for (int i = 0; i < map.MapConfig.ChunkW; i++){
        num = matrixData[j, i];
        strm += num + ",";
    }           
    strm += "],";

以後有空再來查這個問題

64 次阅读 阅读全文

在使用 ILRuntime需要注意

  1. 減少使用 foreach, Dictionary, IEnumerable 的調用會產生額外 GC
  2. 減少調用主工程包含enum參數的函數, 因為在調用的時候會進行值得轉型, 產生額外 GC
  3. ILBinding需要執行, 否則runtime性能會差很多

升級 ILRuntime 到 2.x 版本在 1.6 版本打包Android(package Hotfix.dll by Release)跟 Editor 下的性能非常糟糕,所有的消耗都在 GC 上面,後來升級 2.x 版本就好了

從更新後重新生成 ILBinding 發現修改了 IList 改成 using AutoList,這部分應該是優化了GC回收效率

65 次阅读 阅读全文

建構資源打包到 app 後發現個問題, 遊戲啟動就黑屏, 看了日誌如下
71709-8vuqnmarzhh.png

沒看出甚麼問題重新打個包, 發現一個奇怪的錯誤, 但之前都是這樣打包也沒注意這個情況
06298-lq8keank53.png

查看了系統配置, JAVA_HOME、PATH 都是正常的, 改其他版本 Java 也沒用, 最後發現 Cocos
這個配置是配置到 java 安裝目錄而不是 bin 目錄, 修改如下就好了
27549-w2j5isy8ix.png

44 次阅读 阅读全文