日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Rimworld Mod制作教程1 认识Mod结构

發(fā)布時間:2023/12/8 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Rimworld Mod制作教程1 认识Mod结构 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 廢話
  • 核心內(nèi)容
    • 1 認識mod結構
      • 1.1 mod結構
    • 2 認識開發(fā)工具
      • 2.1 開發(fā)工具
      • 2.2 visual studio開發(fā)環(huán)境
      • 2.3 程序集構建
      • 2.4 修改編譯輸出路徑
      • 2.5 添加引用庫
      • 2.6 編寫代碼及編譯
    • 3 案例
      • 3.1 mod結構構建
      • 3.2 修改簡介
      • 3.3 創(chuàng)建數(shù)據(jù)定義
      • 3.4 編寫C#代碼
      • 3.5 測試
      • 3.6 本地化

廢話

之前就有想嘗試過mod制作,結果在網(wǎng)上看了N多教程還是不知道從何下手。后來想到解鈴還須系鈴人,無奈去看英文的文檔,覺得會詳細一些。
所以本篇參考了 wiki上的一篇教程。但是即便是非常詳細的教程,對于第一次嘗試的人來說還是有很多容易踩坑的地方,所以本篇記錄踩坑過程。

核心內(nèi)容

1 認識mod結構

1.1 mod結構

  • Mod根目錄
    • Abount(存放mod的簡介和mod的標題圖片)
    • Defs(數(shù)據(jù)定義)
    • Assemblies(mod代碼打包后的庫文件)
    • Languages(翻譯的核心目錄)
    • Textures(紋理,mod中對象的素材)
    • Sounds(聲音)
    • Patches(針對其他mod的補丁)
    • Source(mod的源碼,一般沒有作者好心給出源碼,不過我們可以反編譯就是了,很少有加密的mod)

2 認識開發(fā)工具

2.1 開發(fā)工具

visual studio:用于編寫mod核心代碼
vscode:用于編輯xml數(shù)據(jù)定義
dsnpy:用于反編譯原游戲或其他mod的源代碼來學習新姿勢
下載地址請直接百度, 要學會善用搜索引擎

本篇使用以上落后ide開發(fā),目前有更好用的開發(fā)工具jetbrain rider, 體積更輕便,運行更快,并且可以完成上面3個工具的功能,你有什么理由拒絕最新的工具呢?后面會找時間寫一篇教程介紹如何使用rider開發(fā)mod

2.2 visual studio開發(fā)環(huán)境

百度下載,安裝時勾選.net桌面開發(fā),否則無法創(chuàng)建C#程序集,也就是無法打包dll出來。剩下的一路下一步。

2.3 程序集構建

我們在vs上新建一個類庫(.net framework),并把名字改成命名空間SR
wiki的教程提醒我們使用.net framework 3.5的框架版本,我嘗試之后發(fā)現(xiàn)原游戲的版本已經(jīng)高于3.5,于是我反編譯其他mod看了一下其他作者使用的版本,選擇了相同4.6.1

2.4 修改編譯輸出路徑

在properties中點生成,把dll輸出路徑改到我們的mod路徑E:\steam\steamapps\common\RimWorld\Mods\TestGun\Assemblies里

接下來點擊高級,設置內(nèi)部編譯器錯誤報告為無,這樣做是為了避免我們寫出一些小bug導致整個游戲崩潰。

2.5 添加引用庫

點擊引用,選擇原游戲下RimWorld\RimWorldWin64_Data\Managed路徑下UnityEngine,UnityEngine.CoreModule和Assembly-CSharp.dll三個庫文件。

右鍵選擇引用文件,在屬性中取消“復制到本地”,否則編譯時會多復制一堆引用庫文件,而這些文件已經(jīng)被原游戲添加過一次了。

下圖有部分內(nèi)容是錯的,實際不需要引用這么多庫文件,只需要上面提到的3個,以及自帶的部分。

2.6 編寫代碼及編譯

代碼編寫過程略。
右鍵方案點擊build即可打包編譯。

3 案例

此部分暫時只做了解,能看懂多少算多少。

3.1 mod結構構建

為了區(qū)分哪些變量是游戲中的關鍵詞,我更換了一下命名,我們的mod叫做TestGun(測試槍).


按照上面的教程,構建一套mod文件結構。并丟到rimworld的mod文件夾下,在這個文件夾下的mod會被游戲識別,并且可以隨時發(fā)布。

3.2 修改簡介

然后進入About目錄,拖進去一張圖片改名叫Preview.png,再創(chuàng)建一個txt文件,然后改成About.xml,如果你看不到.xml的后綴,在上方點擊查看–選項,取消隱藏已知文件類型的擴展名


然后打開About.xml
復制以下代碼,分別是這個mod的名字,作者,版本和描述

<?xml version="1.0" encoding="utf-8"?> <ModMetaData><name>TestGun</name><author>Shadowrabbit</author><supportedVersions><li>1.1</li></supportedVersions><description>測試創(chuàng)造mod物品</description> </ModMetaData>

完成了這一步,就可以在游戲中看到我們的mod
這里非常推薦一種mod命名規(guī)則:
[{作者名縮寫}{支持的版本號}]{mod名稱}
例如:[SR1.2]Test Gun
這種規(guī)范可以讓人一眼了解這個mod是否適用于當前版本

3.3 創(chuàng)建數(shù)據(jù)定義

接下來在Defs那個文件夾內(nèi)創(chuàng)建一個ThingDefs的文件夾,然后在ThingDefs內(nèi)創(chuàng)建一個xml文件叫做RangedWeapon_TestGun

這是原游戲的命名規(guī)則,不遵守也可以正常運行,但我還是推薦認真一點命名。
接下來在xml中更改一下格式。

<?xml version="1.0" encoding="utf-8"?> <Defs></Defs>

然后我們要去“抄”一下原游戲中某個槍的xml數(shù)據(jù),這樣我們才能知道默認都有哪些數(shù)據(jù)能修改。
我們在vscode中添加一個目錄E:\steam\steamapps\common\RimWorld\Data\Core,這是我的游戲目錄僅供參考,要填自己電腦安裝的目錄

core是原游戲的核心,可以發(fā)現(xiàn)它的結構和我們mod的定義是完全一樣的。打開Defs可以找到所有的物品數(shù)據(jù)定義,但是太多了反而不知道從哪看起。我們在core中搜索Revolver(手槍),把手槍的數(shù)據(jù)復制過來


為了方便觀察,我加了一些翻譯注釋

<?xml version="1.0" encoding="utf-8"?> <!-- 子彈的數(shù)據(jù) --> <Defs> <!-- 繼承了哪個物品 --><ThingDef ParentName="BaseBullet"><!-- 代碼中物品的名字 --><defName>Bullet_Revolver</defName><!-- 游戲中物品顯示的名字 --><label>revolver bullet</label><graphicData><!-- 使用的紋理貼圖 --><texPath>Things/Projectile/Bullet_Small</texPath><!-- 使用哪個圖形類的代碼 --><graphicClass>Graphic_Single</graphicClass></graphicData><projectile><!-- 子彈類型 --><damageDef>Bullet</damageDef><!-- 子彈基礎傷害 --><damageAmountBase>12</damageAmountBase><!-- 取消射擊的反應速度 --><stoppingPower>1</stoppingPower><!-- 子彈的速度 --><speed>55</speed></projectile></ThingDef><!-- 槍的數(shù)據(jù) --><ThingDef ParentName="BaseHumanMakeableGun"><defName>Gun_Revolver</defName><label>revolver</label><!-- 描述 --><description>An ancient pattern double-action revolver. It's not very powerful, but has a decent range for a pistol and is quick on the draw.</description><graphicData><texPath>Things/Item/Equipment/WeaponRanged/Revolver</texPath><graphicClass>Graphic_Single</graphicClass></graphicData><!-- UI縮放 --><uiIconScale>1.4</uiIconScale><soundInteract>Interact_Revolver</soundInteract><!-- 個人猜測是藝術系統(tǒng)的標簽 --><thingSetMakerTags><li>RewardStandardQualitySuper</li></thingSetMakerTags><!-- 基礎屬性 --><statBases><!-- 制作的工作量 --><WorkToMake>4000</WorkToMake><!-- 物品大小 --><Mass>1.4</Mass><!-- 貼臉的命中率 --><AccuracyTouch>0.80</AccuracyTouch><!-- 短距離命中率 --><AccuracyShort>0.75</AccuracyShort><!-- 中距離命中率 --><AccuracyMedium>0.45</AccuracyMedium><!-- 遠距離命中率 --><AccuracyLong>0.35</AccuracyLong><RangedWeapon_Cooldown>1.6</RangedWeapon_Cooldown></statBases><!-- 武器標簽 --><weaponTags><li>SimpleGun</li><li>Revolver</li></weaponTags><!-- 消耗列表 --><costList><Steel>30</Steel><ComponentIndustrial>2</ComponentIndustrial></costList><recipeMaker><!-- 技能需求 --><skillRequirements><Crafting>3</Crafting></skillRequirements></recipeMaker><!-- 動作 --><verbs><li><!-- 射擊 --><verbClass>Verb_Shoot</verbClass><!-- 是否有標準命令 --><hasStandardCommand>true</hasStandardCommand><!-- 子彈類型 --><defaultProjectile>Bullet_Revolver</defaultProjectile><!-- 預熱時間 --><warmupTime>0.3</warmupTime><!-- 射擊距離 --><range>25.9</range><!-- 射擊時使用的音效 --><soundCast>Shot_Revolver</soundCast><!-- 中彈時的音效 --><soundCastTail>GunTail_Light</soundCastTail><!-- 槍口光效的縮放 --><muzzleFlashScale>9</muzzleFlashScale></li></verbs><tools><li><label>grip</label><capacities><li>Blunt</li></capacities><power>9</power><cooldownTime>2</cooldownTime></li><li><label>barrel</label><capacities><li>Blunt</li><li>Poke</li></capacities><power>9</power><cooldownTime>2</cooldownTime></li></tools></ThingDef> </Defs>

到這里為止就可以使用xml修改槍的各種參數(shù),以及發(fā)射什么樣的子彈(需要去core里再查查都有什么子彈,然后填在defaultProjectile里),還可以更換槍的貼圖和音效。更多的物品參數(shù)需要查查wiki,然后翻譯+自己理解,還有多看看core中的xml代碼。
我們本次要制作的是帶有瘟疫效果的槍,我們需要創(chuàng)建一種新的子彈,所以我們要在子彈的def里加幾個新參數(shù)與C#代碼交互
在子彈的xml數(shù)據(jù)中添加

<ThingDef Class="SR.ThingDef_TestBullet" ParentName="BaseBullet">

和三個自定義的新屬性

<!-- 觸發(fā)瘟疫的概率 --><AddHediffChance>0.5</AddHediffChance><!-- Hediff這個詞是游戲里獨一無二的名字,字典里查不到,他的含義是某個部位上的狀態(tài),比如感染,仿生部位,瘟疫Plague是原版游戲其中的一種 --><HediffToAdd>Plague</HediffToAdd><!-- 該物品在C#中使用的邏輯類 --><thingClass>SR.Projectile_PlagueBullet</thingClass>

然后修改子彈的命名避免和原版一樣,修改后如下

<?xml version="1.0" encoding="utf-8"?> <!-- 子彈的數(shù)據(jù) --> <Defs> <!--該物品在C#中使用的數(shù)據(jù)類 繼承了哪個物品 --><ThingDef Class="SR.ThingDef_TestBullet" ParentName="BaseBullet"><!-- 代碼中物品的名字 --><defName>Bullet_TestBullet</defName><!-- 游戲中物品顯示的名字 --><label>測試子彈</label><graphicData><!-- 使用的紋理貼圖 --><texPath>Things/Projectile/Bullet_Small</texPath><!-- 使用哪個圖形類的代碼 --><graphicClass>Graphic_Single</graphicClass></graphicData><projectile><!-- 子彈類型 --><damageDef>Bullet</damageDef><!-- 子彈基礎傷害 --><damageAmountBase>12</damageAmountBase><!-- 取消射擊的反應速度 --><stoppingPower>1</stoppingPower><!-- 子彈的速度 --><speed>55</speed></projectile><!-- 觸發(fā)瘟疫的概率 --><addHediffChance>0.5</addHediffChance><!-- Hediff這個詞是游戲里獨一無二的名字,字典里查不到,他的含義是某個部位上的狀態(tài),比如感染,仿生部位,瘟疫Plague是原版游戲其中的一種,我們定義的這個變量意義是儲存附加給中彈生物的hediff類型 --><hediffToAdd>Plague</hediffToAdd><!-- 該物品在C#中使用的邏輯類 --><thingClass>SR.Projectile_TestBullet</thingClass></ThingDef><!-- 槍的數(shù)據(jù) --><ThingDef ParentName="BaseHumanMakeableGun"><defName>SR_Gun_TestGun</defName><label>影兔的測試槍</label><!-- 描述 --><description>影兔測試瘟疫效果的槍</description><graphicData><texPath>Things/Item/Equipment/WeaponRanged/Revolver</texPath><graphicClass>Graphic_Single</graphicClass></graphicData><!-- UI縮放 --><uiIconScale>1.4</uiIconScale><!-- 交互的音效 --><soundInteract>Interact_Revolver</soundInteract><!-- 個人猜測是藝術系統(tǒng)的標簽 --><thingSetMakerTags><li>RewardStandardQualitySuper</li></thingSetMakerTags><!-- 基礎屬性 --><statBases><!-- 制作的工作量 --><WorkToMake>4000</WorkToMake><!-- 物品大小 --><Mass>1.4</Mass><!-- 貼臉的命中率 --><AccuracyTouch>0.80</AccuracyTouch><!-- 短距離命中率 --><AccuracyShort>0.75</AccuracyShort><!-- 中距離命中率 --><AccuracyMedium>0.45</AccuracyMedium><!-- 遠距離命中率 --><AccuracyLong>0.35</AccuracyLong><RangedWeapon_Cooldown>1.6</RangedWeapon_Cooldown></statBases><!-- 武器標簽 --><weaponTags><li>SimpleGun</li><li>Revolver</li></weaponTags><!-- 消耗列表 --><costList><Steel>30</Steel><ComponentIndustrial>2</ComponentIndustrial></costList><recipeMaker><!-- 技能需求 --><skillRequirements><Crafting>3</Crafting></skillRequirements></recipeMaker><!-- 動作 --><verbs><li><!-- 射擊 --><verbClass>Verb_Shoot</verbClass><!-- 是否有標準命令 --><hasStandardCommand>true</hasStandardCommand><!-- 子彈類型 --><defaultProjectile>Bullet_TestBullet</defaultProjectile><!-- 預熱時間 --><warmupTime>0.3</warmupTime><!-- 射擊距離 --><range>25.9</range><!-- 射擊時使用的音效 --><soundCast>Shot_Revolver</soundCast><!-- 中彈時的音效 --><soundCastTail>GunTail_Light</soundCastTail><!-- 槍口光效的縮放 --><muzzleFlashScale>9</muzzleFlashScale></li></verbs><tools><li><label>grip</label><capacities><li>Blunt</li></capacities><power>9</power><cooldownTime>2</cooldownTime></li><li><label>barrel</label><capacities><li>Blunt</li><li>Poke</li></capacities><power>9</power><cooldownTime>2</cooldownTime></li></tools></ThingDef> </Defs>

為了避免與其他mod命名沖突,我使用SR作為代碼的命名空間,SR.XX表示C#類,SR_XX表示xml數(shù)據(jù),這也是原游戲默認的命名規(guī)范,有兩處SR.XX的數(shù)據(jù)是與C#進行交互的,命名必須一致。
至此xml部分就結束了。

3.4 編寫C#代碼

using RimWorld; using Verse; namespace SR {public class Projectile_TestBullet:Bullet{} } using RimWorld; using Verse;namespace SR {public class ThingDef_TestBullet:ThingDef{} }

我們把新添加的字段寫入數(shù)據(jù)類中,名字要與xml中的一致,不需要給新變量賦默認值,因為會被xml中的數(shù)據(jù)覆蓋,所以addHediffChance運行時為我們在xml中設置的0.5

using RimWorld; using Verse;namespace SR {public class ThingDef_TestBullet:ThingDef{public float addHediffChance; //默認值會被xml覆蓋public HediffDef hediffToAdd;} }

題外話,說一個wiki上關于老版本的問題,如果HediffDef類型的數(shù)據(jù)有默認值的話,在1.0版本之后是會報錯的,因為這個時候HediffDefOf還沒有初始化。不過假如你就是想留默認值也有解決方法,有一個回調函數(shù),我們在回調的時候重新賦值即可。

public override void ResolveReferences() {base.ResolveReferences();hediffToAdd = HediffDefOf.Plague; }

之后是邏輯類,先定義一個變量存它的數(shù)據(jù)

#region data public ThingDef_TestBullet ThingDef_TestBullet {get{//底層通過名字讀取了我們定義的ThingDef_TestBullet這個xml格式的新數(shù)據(jù),并存放到了this.def中,我們將this.def拆箱拿到我們定義好的ThingDef_TestBullet格式數(shù)據(jù)return this.def as ThingDef_TestBullet} } #endregion

我們需要知道原版子彈擊中目標會執(zhí)行什么流程,打開dnspy反編譯Assembly-CSharp.dll,原游戲所有代碼都在Assembly-CSharp.dll中,然后搜索bullet子彈,可以看到子彈的源碼里只有一個可以重載的方法impact,根據(jù)英文的意思知道他是中彈后執(zhí)行的邏輯,里面寫了什么我們暫時不需要關心,我們在測試子彈的類中繼承子彈這個類,然后重寫impact方法,在原邏輯執(zhí)行完畢后添加我們關于瘟疫的設定

關于添加瘟疫的設定,wiki上給出了代碼,我詳細解讀一下貼出來

using RimWorld; using Verse; namespace SR {public class Projectile_TestBullet : Bullet{#region datapublic ThingDef_TestBullet ThingDef_TestBullet{get{//底層通過名字讀取了我們定義的ThingDef_TestBullet這個xml格式的新數(shù)據(jù),并存放到了this.def中,我們將this.def拆箱拿到我們定義好的ThingDef_TestBullet格式數(shù)據(jù)return this.def as ThingDef_TestBullet;}}#endregionprotected override void Impact(Thing hitThing){//子彈的影響,底層實現(xiàn)了傷害 擊殺之類的方法,感興趣的話可以用dnspy反編譯Assembly-Csharp.dll研究里面到底寫了什么base.Impact(hitThing);//絕大多數(shù)mod報錯都是因為沒判斷好非空,寫注釋和判斷非空是好習慣//大佬在這里用了一個語法糖hitThing is Pawn hitPawn//如果hitThing可以被拆箱為Pawn的話 這個值返回true并且會聲明一個變量hitPawn=hitThing as Pawn//否則返回false hitPawn是nullif (ThingDef_TestBullet != null && hitThing != null && hitThing is Pawn hitPawn){var rand = Rand.Value; //這個方法封裝了一個返回0%-100%隨機數(shù)的函數(shù)//觸發(fā)瘟疫if (rand <= ThingDef_TestBullet.addHediffChance){//在屏幕左上角顯示提示,translate方法用于翻譯不同語言之后再說,MessageTypeDefOf要設置一種事件Messages.Message("{0}使用測試槍導致{1}感染瘟疫".Translate(this.launcher.Label,hitPawn.Label),MessageTypeDefOf.NeutralEvent);//判斷一下目標是否已經(jīng)觸發(fā)了瘟疫效果var plagueOnPawn = hitPawn.health?.hediffSet?.GetFirstHediffOfDef(ThingDef_TestBullet.hediffToAdd);//我們?yōu)楸敬斡|發(fā)的瘟疫隨機生成一個嚴重程度var randomSeverity = Rand.Range(0.15f, 0.30f);//已經(jīng)觸發(fā)瘟疫if (plagueOnPawn != null){//嚴重程度疊加,超過100%會即死plagueOnPawn.Severity += randomSeverity;}else{//我們調用HediffMaker.MakeHediff生成一個新的hediff狀態(tài),類型就是我們之前設置過的HediffDefOf.Plague瘟疫類型Hediff hediff = HediffMaker.MakeHediff(ThingDef_TestBullet.hediffToAdd, hitPawn);//設置這個狀態(tài)的嚴重程度hediff.Severity = randomSeverity;//把狀態(tài)添加到被擊中的目標身上hitPawn.health.AddHediff(hediff);}}//本次沒有觸發(fā)else{//這個方法可以在某個位置(這里是被擊中目標的身旁)彈出一小行字,比如未擊中,擊中頭部之類的,也是可以MoteMaker.ThrowText(hitThing.PositionHeld.ToVector3(), hitThing.MapHeld, "{0}未觸發(fā)瘟疫".Translate(hitPawn.Label), 12f);}}}} }

至此新武器的mod就制作完畢了,我們選擇打包生成新的dll,根據(jù)之前設置的目錄,會打包在Assemblies中。

3.5 測試

很遺憾我們的新武器雖然已經(jīng)有了數(shù)據(jù),但是沒有任何方法可以在游戲中自然生成,我們需要借助開發(fā)者模式來測試我們的新槍支,首先打開開發(fā)者模式(記得加載我們的mod),隨便建個新地圖,然后在上方選擇open debug actions menu

在里面找到spawn weapon – SR_Gun_TestGun,然后把它丟在地上,讓我們的角色撿起來,然后對著自己的小人開一槍試試,剛好觸發(fā)了瘟疫效果

未觸發(fā)的log也正常顯示

疊加到100%瘟疫會直接死亡,也是正常的。至此新武器的制作就完成了。

3.6 本地化

本地化就是指翻譯成各種語言,我們把之前message中的內(nèi)容用一個變量代替,讓這個變量在各種語言下顯示不同的文字就可以了。

Messages.Message("{0}使用測試槍導致{1}感染瘟疫".Translate(this.launcher.Label,hitPawn.Label),MessageTypeDefOf.NeutralEvent);

我們更改為

Messages.Message("SR_Message_TestBullet_Success".Translate(this.launcher.Label,hitPawn.Label),MessageTypeDefOf.NeutralEvent);

之后在Languages中創(chuàng)建ChineseSimplified目錄,然后在ChineseSimplified目錄下創(chuàng)建Keyed目錄,再在Keyed目錄下創(chuàng)建一個xml文件,我們命名為SR_TestGun_Keys.xml(名稱可以隨便取,但還是遵循規(guī)范).復制默認的語言數(shù)據(jù)結構

<?xml version="1.0" encoding="utf-8" ?> <LanguageData> </LanguageData>

之后添加兩個新的key,對應我們上一步設置的key名字

<?xml version="1.0" encoding="utf-8" ?> <LanguageData><SR_Message_TestBullet_Success></SR_Message_TestBullet_Success><SR_Mote_TestBullet_Fail></SR_Mote_TestBullet_Fail> </LanguageData>

再把中文的翻譯寫進去

<?xml version="1.0" encoding="utf-8" ?> <LanguageData><SR_Message_TestBullet_Success>{0}使用測試槍導致{1}感染瘟疫</SR_Message_TestBullet_Success><SR_Mote_TestBullet_Fail>{0}未觸發(fā)瘟疫</SR_Mote_TestBullet_Fail> </LanguageData>

至此中文版本就完成了,如果要加入英文版的話,就在Luaguages下創(chuàng)建English目錄等等,然后創(chuàng)建相同的文件,在值里填入英文對應的文本即可,游戲會根據(jù)用戶選擇的語言自動選擇語言數(shù)據(jù)加載。
源碼下載

如果這篇文章對你有幫助,點贊收藏支持一下唄!

總結

以上是生活随笔為你收集整理的Rimworld Mod制作教程1 认识Mod结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。