MOD製作教程 MOD原始碼解析及開發指南 - 三、進階篇 城市:天際線

來源:樂享遊戲吧 1.52W

三、進階篇

三、進階篇 城市:天際線 MOD製作教程 MOD原始碼解析及開發指南

然後就是我們的hack時間了。這部分沒有任何官方說明,出現的bug也只能靠我們自己解決,出現任何奇怪的事情都是正常的。然後我們繼續。

要替換官方的BusAI,最簡單的方法我相信大家已經猜到了,就是繼承官方的AI,然後僅僅修改我們需要修改的部分就好了。那麼,我也是這麼幹的。

看程式碼:

using ColossalFramework;

using UnityEngine;

namespace SuperBigTransport

{

class BigBusAI : BusAI, IAIReplacement//繼承官方的BusAI

{

public void CopyFrom(BusAI ai)//我們自己定義的介面,主要用於兩個AI的屬性對拷

{

m_passengerCapacity = Mod.unit_number * 5;//這裡是公交的容量,但是這個數字僅僅是顯示用的,實際上,能上多少人不已這裡為準。竊以為,這是官方程式碼的bug

m_ticketPrice = ai.m_ticketPrice;//車票多少錢,這個我沒改過,不知道是不是隻改這裡就是增加車票收入,有興趣的同學可以試試。

m_info = ai.m_info;//info,就是bus的基本資訊,busInfo,前面提到過的,忘了的話自己回去看。但是不管它是什麼,拷過來就好了

}

public override bool ArriveAtDestination(ushort vehicleID, ref Vehicle vehicleData)//複寫官方的車輛到站後的處理邏輯。官方的方法裡,車到站以後有很多的判定步驟,要判斷該下多少人,能上多少人,是否是終點站,等等一大堆。我沒把握能全部寫好,而能上多少人這個方法它又是private的(日),所以,只能改這個,並且最後一步還的呼叫base的方法。

{

var citizenManager = Singleton.instance;//OK這裡就是呼叫各種Manager單例的方法,前面欠大家的程式碼這裡補上了。

var unitId = vehicleData.m_citizenUnits;//好了,這裡涉及到另一件事情,是citizen所特有的概念,citizenUnit,前面的public const int unit_number = 16;就是跟這個相關的。這裡呢,每個citizenUnit裡面能裝5個citizen,一個citizen可以被裝在多個citizenUnit裡,裝的也僅僅是引用。citizenUnit是一個連結串列結構,citizenUnit有一個屬性是nextUnit,就是下一個citizenUnit的引用,如果沒有下一個,就是0,說明連結串列結束。那麼這個citizenUnit用在哪裡呢?這麼說,所有能裝人的地方,本質上就是這個citizenUnit有多長的結構。每輛車、每個建築物,都有一個citizenUnit的引用,指向的是第一個citizenUnit的位置。所以,我們要增容,就是擴充套件這個citizenUnit。

var cu = citizenManager.m_units.m_buffer[unitId];//這行程式碼說明,citizenUnit也是由CitizenManager來統一管理的

int i = 1;

while (cu.m_nextUnit>0) {//判一下當前的容量數是多少

i++;

cu = citizenManager.m_units.m_buffer[cu.m_nextUnit];

}

if (i != Mod.unit_number) {//如果不等於預期,就改

uint firstId;

var random = new ColossalFramework.Math.Randomizer();

citizenManager.CreateUnits(out firstId, ref random, 0, vehicleID, 0, 0, 0, Mod.unit_number * 5, 0);//citizenUnit既然是由CitizenManager來統一管理的,那麼建立肯定也是由CitizenManager來統一做的。我們簡單的在這裡建立了一個符合我們預期長度的citizenUnit

vehicleData.m_citizenUnits = firstId;//然後粗暴的直接替換

//citizenManager.ReleaseUnits(unitId);//這裡不能釋放,釋放了市民就找不到路了。釋放了有什麼效果請自行觀察。

}

return base.ArriveAtDestination(vehicleID, ref vehicleData);

}

}

}

好了,這裡就是我們增容的核心程式碼了。那麼現在有一個bug,就是公交會閃。在這裡我表示我非常的冤枉,跟我真的沒啥關係。。。。我沒動frame..我只是替換了個數組。

所以,這個替換是非常生硬的,直接的後果就是會導致存檔發生變化。即使關閉了mod,也無法改變已經客觀存在的連結串列結構。所以我說嘛。。官方偷懶。。不好好的呼叫那個容積屬性進行判斷。。非要搞陣列,還是連結串列結構的。。。真是無語。

然後,上面只是公交車的,下面是地鐵和客運火車的。我直接貼程式碼了,因為結構差不多,我就不解釋了。有一個小bug,會導致一個不合理的現象,但是很隱蔽,不知道大家能發現麼?

using ColossalFramework;

using System.Collections.Generic;

namespace SuperBigTransport

{

class BigPassengerTrainAI : PassengerTrainAI, IAIReplacement

{

public void CopyFrom(PassengerTrainAI ai)

{

m_passengerCapacity = Mod.unit_number * 5;

m_ticketPrice = ai.m_ticketPrice;

m_info = ai.m_info;

m_arriveEffect = ai.m_arriveEffect;

m_transportInfo = ai.m_transportInfo;

}

CitizenManager citizenManager = Singleton.instance;

public override bool ArriveAtDestination(ushort vehicleID, ref Vehicle vehicleData)

{

var unitId = vehicleData.m_citizenUnits;

var cu = citizenManager.m_units.m_buffer[unitId];

int i = 1;

while (cu.m_nextUnit > 0)

{

i++;

cu = citizenManager.m_units.m_buffer[cu.m_nextUnit];

}

uint firstId;

int n;

if (i < Mod.unit_number)

{

var random = new ColossalFramework.Math.Randomizer();

if (vehicleData.m_transferType==39)//metro

{

n = (Mod.unit_number-i) * 5*6 + 30;

citizenManager.CreateUnits(out firstId, ref random, 0, vehicleData.GetFirstVehicle(vehicleID), 0, 0, 0, n, 0);

}else

{

n = (Mod.unit_number-i) * 5 *8 + 30;

citizenManager.CreateUnits(out firstId, ref random, 0, vehicleData.GetFirstVehicle(vehicleID), 0, 0, 0, n, 0);

}

vehicleData.m_citizenUnits = firstId;

//citizenManager.ReleaseUnits(unitId);

}

else if (i > Mod.unit_number)

{

var random = new ColossalFramework.Math.Randomizer();

if (vehicleData.m_transferType == 39)//metro

{

firstId = citizenManager.m_units.m_buffer[unitId].m_nextUnit;

citizenManager.ReleaseUnits(unitId);

vehicleData.m_citizenUnits = firstId;

n = (Mod.unit_number - 6) * 5 * 6 + 30;

}

else

{

firstId = citizenManager.m_units.m_buffer[unitId].m_nextUnit;

citizenManager.ReleaseUnits(unitId);

vehicleData.m_citizenUnits = firstId;

n = (Mod.unit_number - 6) * 5 * 8 + 30;

}

citizenManager.CreateUnits(out firstId, ref random, 0, vehicleData.GetFirstVehicle(vehicleID), 0, 0, 0, n, 0);

vehicleData.m_citizenUnits = firstId;

}

return base.ArriveAtDestination(vehicleID, ref vehicleData);

}

}

}

熱門標籤