變數‎ > ‎

低容量存檔系統

這招應該沒人再用吧orz


第一個有存檔系統的同人由鷹眼製作,存檔系統隨即成為各名導演的新寵,甚至連新作家也蠢蠢欲試
接下來介紹的存檔系統,是由本中心的編輯們聯合創作,不會披露其他作家的存檔系統
此處教的存檔系統不計加密,不計輸出用的字串,只需37容量,酷吧(X
在下面的例子連同HKID加密法,也只是50容量,連300容量的同人也可以加入存檔系統OAO
電腦夠強的話,2秒就能有輸出

存檔系統看似複雜,其實很簡單:

存檔說穿了你只要會一點密碼學就會了030
只是光暈同仁那種的要轉換比較麻煩就是

上面可不是某FK亂說的,是某大師級同人作家--連小哈都忍不推薦他的同人--說的哦
看來某FK繼範圍效果後,會再被他追殺(X

入正題
存檔主要分兩大部分:
一、存檔
二、讀檔

在下面,我們會用一個例子來教大家
存檔碼數量:2
 需存檔的變數名稱 explv money hp  weapon.0weapon.1  job
 賦值上限 999999 9999 999 
 變數現值 1111 22 3333 444 5 6 7

========================================================

一、存檔

這部分有三個步驟
宣告+串聯->(加密)->輸出存檔碼        
//括號內的你大可不加,不過被玩家猜中了你存檔系統是這樣的話,他們就可以拿你的讀檔系統當外掛



1.宣告+串聯

這兒我們會用AsshoIe的字串宣告整數法,把各個變數串在一起。
但需要注意的是,最多串成8個數位,因為整數是有數位限制的,ie:-2147483648 <= integer <= 2147483647
所以在弄存檔時要計劃好哪些數位存哪些資料。本例題會這樣存,各位可以參考
 數位 9876543210
 save.0 0 exp exp exp exp job hp hp hp 補碼(加密用)
 save.1 0 money money money money weapon.0 weapon.1 lv lv 補碼(加密用)

換個話來說,save.0和save.1的個位數都是拿來儲存補碼,
save.0的十位數至千位數是拿來儲存hp,萬位數來存job,十萬至億位數拿來存exp;
save.1的十位數至百位數拿來存lv,如此類推。。。

但是,如果直接使用字串宣告法,若變數的數位不足則可能造成讀取錯誤,所以在串聯前需要宣告,用0補回數位
還有需要注要的是,負數和空值(null)不能夠用這招串聯,所以這招最便宜個位數的存檔


現在來介紹這部分的整個原理
首先要給上面那些變數來一個變身,給他們每人一個編號,由右至左,上至下的編
怎編呢,看下文

通項-General Term    (記得用null變數宣告法省容量):        //後的是解說
save.{m}.{n}.value=var    //第m個存檔碼的第n個(由右至左)變數的數值 = 對應變數(見上表)的數值
save.{m}.{n}.E=var.E        //第m個存檔碼的第n個變數的數位變數的數位
save.{m}.varSum = ?       //第m個存檔碼需要存的變數總數

真正應用時的樣子: 
save.0.0.value = hp        //第1個存檔碼要存的第1個變數是hp(我們只對它的值感興趣)
save.0.0.E = 3                //第1個存檔碼的第1個變數(hp)佔用三個數字

save.0.1.value = job        //第1個存檔碼要存的第2個變數是job
save.0.1.E = 1                //第1個存檔碼的第2個變數(job)佔用一個數字

save.0.2.value = exp        //第1個存檔碼要存的第3個變數是exp
save.0.2.E = 4                //第1個存檔碼的第3個變數(exp)佔用四個數字

save.0.varSum = 3         //第1個存檔碼一共要存三個變數
現在用同一個方法宣告save.1吧
 
編好號碼,他們就像拿了籌,排隊進餐廳
取籌後,進餐也有一個既定程序:下單->取餐->吃完->下一位
那麼,說一說串聯的程序吧:
1.取出「第1個存檔碼要存的第1個變數第1個數位」(個位數),塞去「第1個存檔碼第1個數位
    ie save.0.0save.0.0.value%10
        save.0%{save.0.0}%%{save.0}%;
        
2.削走第1個存檔碼要存的第1個變數第1個值,令「第1個存檔碼要存的第1個變數第2個值」變成「第1個存檔碼要存的第1個變數第1個值
    save.0.0.value=save.0.0.value/10;    //削走個位數

3.重覆 1, 2 直至「第1個存檔碼要存的第1個變數」的所有數位儲存完畢

4.換上「第1個存檔碼要存的下一個變數」,重覆1, 2, 3直至「第1個存檔碼」要存的所有數位儲存完畢

5.換上「下一個存檔碼要存的第1個變數」,重覆1, 2, 3, 4直至所有存檔碼儲存完畢

程式化了的槪念(不看也沒關係): 
for (int i = 0; i<2;i++){                                        //遞增重複直至兩個存檔碼儲存完畢
    int h=0;
    for (int j = 0; j<save.[i].varSum;j++){                //遞增重複直至編號為i的存檔碼存好它該存的變數
        for (int k = 0; k<save.[i].[j].E;k++){                //遞增重複直至存檔碼i的第j個變數的數值儲存完畢
            h++;                                                          //save.n的累積數位
            save.{i}.{h}=save.{i}.{j}.value%10;                        //取出第 i 個存檔碼要存的第 j 個變數」的個位數並儲存為「存檔碼 i 的第 h 個數位」的值
            save.{i} = %{save.{i}.{h}}%%{save.{i}}%;                        //字串宣告整數法:將上面的值疊在save.{i}的前面
            save.{i}.{j}.value=save.{i}.{j}.value/10;   // (無條件捨去)    //削走第 i 個存檔碼要存的第 j 個變數」的個位數
}}}

上面看不懂不要緊,看懂下面同人陣化了的程式碼就可以:
迷聲:怎麼更難理解了....

事件-initialize
[動作] i = 0                            //用作分辨save.0和save.1
[動作] j = 0                            //用作分辨save.{i}內的各個大值,如save.0中的第一個變數是hp
[動作 ]k = 0

事件-stack
[檢查] i<2
[動作] h = h+1;                                                                      //save.n的累積數位
[動作] save.{i}.{h} = save.{i}.{j}.value%10;                                  //取出第 i 個存檔碼要存的第 j 個變數」的個位數並儲存為「存檔碼 i 的第 h 個數位」的值
[動作] save.{i} = %{save.{i}.{h}}%%{save.{i}}%;                              //字串宣告整數法:將上面的值疊在save.{i}的前面
[動作] save.{i}.{j}.value = save.{i}.{j}.value/10;    (無條件捨去)    //削走第 i 個存檔碼要存的第 j 個變數」的個位數
[動作] h = h%8;                                                                        //當h到8時歸0(已知每個存檔碼只會存8個數位)
[動作] k = k+1;                                                                        //記錄第 i 個存檔碼要存的第 j 個變數」要存下一個位
[動作] j.plus = k/save.{i}.{j}.E;(無條件捨去)                                 //如果第 i 個存檔碼要存的第 j 個變數」的所有數位存完,就輸出1,否則0
[動作] k = k%save.{i}.{j}.E;                                                         //如果第 i 個存檔碼要存的第 j 個變數」的數位儲存完畢的話,就將k歸0、
[動作] j = j+j.plus;                                                                   //兼且移師下一個要存的變數
[動作] i.plus = j/save.{i}.varSum;(無條件捨去)                             //如果第 i 個存檔碼」要存的所有變數存完,就輸出1,否則0
[動作] j = j%save.{i}.varSum;                                                      //如果第 i 個存檔碼」的變數儲存完畢的話,就將j歸0、
[動作] i = i+i.plus;                                                                    //兼移師下一個存檔碼


事件-code    //加密用事件
[檢查]i>=2
。。。

串聯後的save.0會是11117444;save.1是33335622

-----------------------------------------------------------------------------

2.加密
關於加密,

網路常用加密法有RSA加密演算法,奇偶校驗位(反用作加密),

當然,我們不用這麼難的加密法,

在存檔系統中,

某AsshoIe建議用HKID[1],ISBN-13[2]等加密法(相對簡單

要不然也可以自創一套加密系統,讓駭客摸不著頭腦/_>\

以上讓大家參考

總之我們要的加密法輸出一個單位數字,然後放到存檔碼當個位數

save.0=%{save.0}%%{補碼0-由加密系統提供}%
save.1=%{save.1}%%{補碼1-由加密系統提供}%

如果你嫌這招防得還不夠嚴密,敬請期待之後某FK會再另頁談的數字掩飾法


如果你想所有存檔碼都使用同一種加密法,而這個加密法也耗你很多容量,某FK建議你改一改存檔的流程為:
串聯save.0->加密save.0->串聯save.1->加密save.1->輸出

但同時讀檔時也要改為:
拆解save.0->解密save.0->拆解save.1->解密save.1->宣告



//[1]:HKID的加密是7個位值+1個檢驗數位 ,方法大概是 檢驗數位 =11-7個位值的權數 mod 11 (mod指數)

//[2]:ISBN-13加密是12個位值+1個檢驗數位 ,方法大概是 檢驗數位 =10-12個位值權數的個位數(e.g 18的個位數是8)

3.輸出存檔碼
把最後的存檔碼放到任務提示,搞定~

========================================================

二、讀檔

這部分同樣有三個步驟
輸入存檔碼->拆解/解密->宣告
這明顯只是反轉了存檔的步驟(X

-----------------------------------------------------------------------------

1.輸入存檔碼

讓玩家依次序說出存檔碼,存至save.0和save.1中

[事件]load
n = 0

[事件]read
n<2
save.{n} = 玩家說話內容
n=n+1

-----------------------------------------------------------------------------

2.拆解/解密

解密即是檢查存檔碼是不是源自你的同人,而不是瞎猜
如果你的加密系統有抽取數位作補碼,則要先進行拆解,再解密
總之各位要靈活變通


現在講一講拆解原理吧
1.取出存檔碼的個位數,放到save.0.0
2.去掉存檔碼的個位數
3.重複1和2,不過不是放到save.0.0,而是save.0.1,再下一次重複則是save.0.2,如此類推
4.為save.1重複1, 2, 3

程式化了的槪念(不看也沒關係):

for (int i=0; i<2; i++){
for (int j=0; j<9; j++){            //從數位重覆10次
save[i][j]=save[i]%10;
save[i] = save[i] /10;
  }
}

上面看不懂不要緊,看懂下面同人陣化了的程式碼就可以:

事件-initailize
[動作] i = 0;
[動作] j = 0;

事件-cut
[檢查]i<2
[動作] save.{i}.{j} = save.{i}%10;
[動作] save.{i} = save.{i} /10;
[動作] j=j+1;
[動作] i.plus = j/9;
[動作] j = j%9;
[動作] i = i+i.plus;

事件-decode    //解密用事件
[檢查]i>=2
。。。


然後檢查一下補碼(此處存檔碼0和1的補碼分別已自動存至save.0.0和save.1.0)符不符合你的加密法,
符合的話進入下一個階段,否則弄死他的flash(誤
而此處取出補碼的過程,如果你頭腦清晰,你會發現可以重用弄存檔部分時的那個(X


-----------------------------------------------------------------------------


3.宣告

用null變數命名法或字串宣告法把存檔碼內容塞回變數i.e
[save.1.3]!=[null]   儲存為waepon.1
exp = %{save.0.8}%%{save.0.7}%%{save.0.6}%%{save.0.5}%
如此類推
記得參考上文教存檔時弄出來的表

-----------------------------------------------------------------------------

以上就是存檔系統的基本原理,希望能幫到大家~

========================================================

存檔漏洞

至於存檔系統被人肆意公開的問題,

相信有修電腦科的人也會知公鑰和私讑,

玩家的名字可作私讑,

再用私讑進行加密不就行嗎?(刪

可是我們拿不出LC.*那串私讑= =


某FK倒是有一個辦法,可惜只有我們偉大的副編輯,戀愛旋律,有能力弄這招了/_>\

首先,我們需要架設一個有database的網頁( google site 88不能用了。例如FK這種電腦白痴也88了,不懂得弄啊)

然後讓玩家用電郵註冊,還要驗証不是機械人(機械人太易弄了),並記錄玩家的IP地址

每個玩家只能拿到一組內有ID的起初存檔碼

ID不能太複雜,一個五位數就足夠有餘了

沒有存檔碼不能存檔

在同人取得的存檔必須經過網頁解碼,再重新加密才可以再在同人使用

哪個仁兄公開存檔碼的話,在server禁了他的ID和IP他就GG了/_>\

但問題是,同人界似乎沒人懂得弄這招(X

========================================================

資料壓縮

方法一:基數轉換法 (中三程度、進制應用,主要應用在布冧)

一天,某Asshole乂命運在想,

如何把資料壓縮呢?

在一般圖像資料壓縮上,我們採用的是有損壓縮,在純數字方面,似乎無法應用「有損壓縮」

所以,Asshole乂命運將教大家什麼是「無損壓縮」

雖然以10為基底的數字沒法壓縮,但在以2為基底的數字 卻可以壓縮成 以10為基底的數字 !

以下是一些例子:

[動作] Asshole.data.0=1[3]
[動作] Asshole.data.1=1
[動作] Asshole.data.2=1[4]

//[3]:以2為基底的數字有 0 及 1
//[4]:資料壓縮技術以三個 二進制 變數為一組,所以資料壓縮比為 1:3

[動作] compression=Asshole.data.2 *(2^2)[5]
[動作] compression=Asshole.data.1 *(2^1)
[動作] compression=Asshole.data.0 *(2^0)

//[5]:此處可想像把111(2) 轉成 十進制,結果得出7(10),注意!括號指進制而非乘法

經過一番運算,我們成功把111(2)壓縮成7(10),

比較資料長度,7佔一位,而111佔三位,可見資料壓縮成功,而比率更是1:3!

只要用短算法,即可把 7(10) 轉回 111(2),

0=000 1=001 2=010 3=011 4=100 5=101 6=110 7=111,

順帶一提,一個整數最多只能儲存32個2進制的數字,但在正整數限制下只能存31個

(本招適用於一事件等存在 0及1 運算任務中)


方法二:低有效值法 (中二數學第一課程度,我記得很清楚,因為這課的小測我拿了滿分,BTW主要應用在大數值上)

這招是用兩個數位來存多位數,是純數字的「有損壓縮」        (我好壞啊,在串AsshoIe)

如 5984165498 ,只取一個有效值,變成5*10^9,然後儲存5和9

PS:(此處用了無條件捨去而不用四捨五入,以免被人拿來刷等。但是有作家會照用四捨五入,不過玩家要在遊戲開始一段時間後才准存檔。自行取捨吧~)

讀取時,則用5*10^9的算式得回5000000000,一堆數位都丟了/_>\



========================================================

進階-大資料存檔系統

以往我們被限制是因為我們直接使用了檢查-說話內容-中的儲存數值

這個數值必定是以整數的形式儲存,但整數的上限是2^31+1,所以存檔碼的長度不能超過10個位,且少於2^31+1

只要要多做少少加工,不直接使用這功能,就可以讓存檔碼的長度達至30個位(任務提示顯示不到超過30個字元的字串,不然可以有64個位)

運作原理:
輸出存檔碼的原理不用多說,跟原本的相同
不同的是讀檔

當玩家說出存檔碼時,系統就將數字0至9遂個跟玩家的說話內容作比對
若發現比對的內容跟玩家說話內容一致,便存至陣列(用作讀取資料)和字串(用作讀取存檔碼),下次比對之前會將數字附在這個字串上,以繼承之前的比對結果
整個過程就好像DNA的複製過程(由組合TAC開始比對,A對T,C對G;但此處由不知何處開始比對,0對0,1對1,如此類推)。例:

玩家說:314159265359
系統比對出來的存檔碼(下稱存檔碼):null(空值)
系統從0-9遂個比對:
=>沒有找到0
=>找到1
存檔碼=1
儲存至陣列:say.0=1    //第0個數字是1,設第一個找到的數字的位置是零位

玩家說:314159265359
存檔碼:-1----------

再遂個比:
玩家說:314159265359
存檔碼:01----------    =>不對
存檔碼:-10---------    =>不對

玩家說:314159265359
存檔碼:11----------    =>不對
存檔碼:-11---------    =>不對

玩家說:314159265359
存檔碼:21----------    =>不對
存檔碼:-12---------    =>不對

玩家說:314159265359
存檔碼:31----------    =>對上了
儲存至陣列:say.-1=3    //第1個數字是3
之後的比對會在31前或後再加數字

繼續找:
玩家說:-314159265359
存檔碼:031----------    =>不對
存檔碼:-310---------    =>不對

玩家說:-314159265359
存檔碼:131----------    =>不對
存檔碼:-311---------    =>不對

玩家說:-314159265359
存檔碼:231----------    =>不對
存檔碼:-312---------    =>不對

如此類推

再比對不出數字就表示所有數字已讀取完畢
之後整理一下那個陣列,回復由0開始的格式,就可以回歸常規的存檔系統
這招也可以拿來儲存玩家的說話內容為字串,詳情請見此頁
不過每個字元需要1容量,就請各位斟酌考慮了

Author profile image
FK 人 (Facebook人)
Mar 20, 2016, 10:25:10 AM(edited: Mar 20, 2016, 10:46:03 AM)
偷偷把所需容量改了(X
Author profile image
FK 人 (Facebook人)
原來是我計錯數了,真的只用37容量,我真失敗(畫圈圈
Mar 20, 2016, 10:46:03 AM
Author profile image
FK 人 (Facebook人)
Mar 20, 2016, 9:22:57 AM(edited: Mar 20, 2016, 11:55:38 AM)
數字的有損儲存可以這樣弄:
Author profile image
FK 人 (Facebook人)
如果我們要存的是A,A則可以這樣表達:

A=B*10^C+......

B上限:9
C上限:9
除第一個數位外,其餘數位我們都不重視,全數無條件捨去 (如果四捨五入的話,小心被人拿來刷經驗刷等)

所以現在我們不直接存A,改為存B和C

即是只用2個數位,就能儲存9*10^9,即 9000000000,但000000000是捨棄數位後的數字,即是我們可以用兩個數位來儲存上限為9999999999的數字(但整數的上限只有2147483647)

夠大不?

只不過第一個9之後的數字全丟了/_>\
Mar 20, 2016, 9:25:12 AM(edited: Mar 20, 2016, 10:18:31 AM)
Author profile image
Ka Kit Lau
我的壓縮比是固定(刪刪
Mar 20, 2016, 11:55:38 AM
Author profile image
Ka Kit Lau
Mar 17, 2016, 1:03:43 PM
而肆意公開的問題,

相信有修電腦科的人也會知公鑰和私讑,

玩家的名字可作私讑,

再用私讑進行加密不就行嗎?(刪

可是我們拿不出LC.*那串私讑= =
Author profile image
Ka Kit Lau
Mar 17, 2016, 12:57:01 PM
關於加密,

網路常用加密法有RSA加密演算法,奇偶校驗位(反用作加密),

當然,我們不用這麼難的加密法,

在存檔系統中,

我建議用HKID,ISBN-13等加密法(相對簡單

以上讓大家參考