İçeriğe geç

Export'lar ve state bag'ler

İki giriş yolu var ve ucuz olanı önce.

phoneapi <id>, sunucu konsolunda bir oyuncu için aşağıdaki her şeyi yazdırır. Buradaki bir şey beklediğiniz yanıtı vermiyorsa, daha fazla okumadan önce bunu çalıştırın — hangi tarafın yanlış olduğunu tahmin etmekten daha hızlıdır.

State bag’ler — hiçbir şeye mal olmayan yanıtlar

Section titled “State bag’ler — hiçbir şeye mal olmayan yanıtlar”

Bir state bag için callback, olay veya bu kaynakla bir anlaşma gerekmez. Soran her makinede okunan bir tablodur, altınızda bu kaynak yeniden başlatılsa bile hayatta kalır ve client’ta da server’da da aynı şekilde çalışır.

-- server
if Player(src).state.onCallWith then ... end
-- client, about somebody else
if Player(GetPlayerFromServerId(id)).state.phoneOpen then ... end
BagTür
phoneNumberstringtaşıdıkları telefonun numarası
phoneNamestringo telefon birini aradığında gösterdiği ad
phoneDevicestring | nileşya modunda bunun hangi telefon eşyası olduğu. Telefonlar karakterlere aitken nil
phoneOpenbooleantelefon dışarıda ve ekranda
onCallWithnumber | nilhattın diğer ucundaki source
callAnsweredbooleanbiri açtı. Hâlâ çalıyorken false
speakerphoneboolean
mutedCallbooleankendilerini sessize aldılar
otherMutedCallbooleandiğer uç kendini sessize aldı
flashlightbooleanel fenerleri açık. Her client ışını o ped üzerinde çizer
phoneCamerabooleanbir vizör açık: bir fotoğraf çekmek üzereler
phoneSignalnumberkaç çubuk, 0 ile Config.Signal.Bars arası. 0, şehrin ulaşamadığı bir telefon demektir

Bilmeye değer üç şey:

Sunucu tarafından yazılırlar. Client de hepsini bilir ve daha az satırla yayınlayabilirdi, ancak bir client hepsi hakkında yalan söyleyebilir ve bir anticheat’in okuduğu bir bag’in okunmaya değer olması gerekir.

Çalmak, bir aramada olmak sayılır. onCallWith, bir telefon çaldığı anda ayarlanır, çünkü hat meşguldür — henüz doğru olmayan şey, birinin açmış olmasıdır ve bu callAnswered’dır.

onCallWith, gerçek bir arama sırasında nil olabilir. Diğer uç, şehirdeki bir oyuncu yerine birinin tarayıcısı olabilir. callAnswered yine true’dur; yalnızca adı verilecek bir source yoktur.

El feneri gerçekten bir şeyi aydınlatana kadar bir flashlight bag’i yoktu; gerekçe, her zaman false olan bir bag’in hiç olmayan bir bag’den daha kötü olduğuydu — biri eksik bir özelliktir, diğeri yanlış bir yanıt. Artık bir şeyi aydınlatıyor, dolayısıyla yayınlanıyor.

exports.mic_phone:GetNumber(src) --> '555-010-2048'
exports.mic_phone:GetName(src) --> 'Jean Dupont'
exports.mic_phone:GetIdentifier(src) --> 'char1:abc…' or 'device:abc…' in item mode
exports.mic_phone:GetDevice(src) --> the phone item's id, or nil
exports.mic_phone:HasPhone(src) --> are they carrying one at all
exports.mic_phone:IsOpen(src)
exports.mic_phone:IsInCall(src)
exports.mic_phone:CallWith(src) --> the other source, or nil
exports.mic_phone:GetSource(number) --> src, for a number
exports.mic_phone:NumberOf(identifier) --> works for somebody who is not online
exports.mic_phone:IdentifierOf(number)
exports.mic_phone:Call(src, number) --> rings it from their phone, exactly as dialling would
exports.mic_phone:EndCall(src)
exports.mic_phone:AddContact(src, name, number, { email =, notes =, favorite = })
exports.mic_phone:RemoveContact(src, number)
exports.mic_phone:SendNotification(src, { app =, title =, body = })
exports.mic_phone:OpenApp(src, 'messages')
exports.mic_phone:OpenPhone(src) / ClosePhone(src)
exports.mic_phone:SendMessage(number, text, from)
exports.mic_phone:SendMail(identifierOrNumber, fromName, fromAddress, subject, body)
exports.mic_phone:SendInvoice(senderSrc, targetNumber, label, amount, society)

Call, telefonun kendisine söylenecek olanı döndürür — { ok = false, reason = 'busy' }, 'airplane', 'unknown', 'offline' — çünkü telefonun kendi arama tuşlarının çalıştırdığı aynı işleyiciyi çalıştırır. Yanlış yapılabilecek tek bir kod yolu ve tek bir kurallar kümesi vardır.

Yanıtı nil olan bir export hiç değer döndürmez; nil bir değer değil. Doğrudan bir argüman listesine konduğunda "nil" olmaz — listeyi kısaltır. Önce bir yerel değişkene koyun:

local with = exports.mic_phone:CallWith(src) -- and not print(exports.mic_phone:CallWith(src), x)

Başka bir kaynağın kendi başına yanıtlamak zorunda kaldığı sorular. Her biri telefonun zaten yaptığı bir aramadır; dolayısıyla yanlış yapılabilecek tek bir kod yolu ve tek bir kurallar kümesi vardır.

exports.mic_phone:GetBattery(src) --> 0-100, or nil when this city has no battery at all
exports.mic_phone:SetBattery(src, 40) --> your own charger, or a story that drains one
exports.mic_phone:IsCharging(src)
exports.mic_phone:HasAirplaneMode(src) --> the city cannot reach them; their own phone still works
exports.mic_phone:GetSignal(src) --> 0 to Config.Signal.Bars. Also the `phoneSignal` state bag
exports.mic_phone:SetJammed(src, true) --> takes their bars away: a heist, a prison, a story
exports.mic_phone:GetGallery(src) --> every picture: { id, url, width, height, kind, created }
exports.mic_phone:AddPhoto(src, url, w, h) --> puts one in it, and it appears without a reboot
exports.mic_phone:GetContacts(src)
exports.mic_phone:GetInvoices(src) --> every invoice on that phone, paid and unpaid
exports.mic_phone:UnpaidInvoices(src) --> count, total
exports.mic_phone:SendLocation(number, x, y, 'The docks', from) --> a map pin in a conversation
exports.mic_phone:GetSocialHandle(src, 'instapic') --> 'nightshift', or nil if they never signed up
exports.mic_phone:SocialPost(src, 'twixel', { text = 'Anybody seen a blue Sultan?' })
exports.mic_phone:SetVerified(src, 'twixel', true) --> the tick beside their name, per app
exports.mic_phone:GetRadioChannel(src) --> 12, or nil
exports.mic_phone:SetRadioChannel(src, 12) --> 0 takes them off it

GetBattery’nin nil yanıtı vermesi, 0 yanıtı vermesiyle aynı şey değildir: nil, bu sunucunun bataryayı hiç açmadığı anlamına gelir. İkisini aynı sayan bir script, telefonun asla bitmediği bir şehirde birinin ambulans çağırmasını engeller.

AddPhoto, URL’yi bu sunucunun izin verdiği host’lara karşı kontrol eder; tıpkı kameranın çektiği bir fotoğrafın kontrol edilmesi gibi. Herhangi bir adresi gösterecek bir galeri, birinin her şeye yönlendirebileceği bir galeridir.

SocialPost ve SetRadioChannel, telefonun kendi işleyicilerini çalıştırır; dolayısıyla ekranın uyduğu şeylere uyarlar: o uygulamada hesap yoksa gönderi yoktur ve bu mesleğin sahip olamayacağı bir kanal burada da reddedilir.

Altı coin; fiyatları, bir client’tan kimsenin erişemeyeceği bir zamanlayıcıyla sunucu tarafından belirlenir. Aşağıdaki her şey coin ve para cinsindendir — asla kaynağın saydığı milyonda birlik birimlerle değil — dolayısıyla birine bir şeyin dörtte birini ödeyen bir script 0.25 der.

exports.mic_phone:Coins() --> every coin: id, name, symbol, price, change, window, history
exports.mic_phone:CoinPrice('santo') --> 42137.55, in money. nil when there is no such coin
exports.mic_phone:GetCrypto(src, 'santo') --> 0.4218
exports.mic_phone:GetCryptoValue(src) --> what their whole portfolio is worth, in money
exports.mic_phone:AddCrypto(src, 'omen', 12.5) --> true when it landed
exports.mic_phone:RemoveCrypto(src, 'omen', 12.5) --> false when they did not have it, and nothing moves
exports.mic_phone:SetCoinPrice('omen', 0.4) --> move the market for a story

RemoveCrypto, negatife düşmek yerine reddeder; dolayısıyla yanıtı aynı zamanda “ödeyebildi mi” sorusunun yanıtıdır — coin karşılığı bir şey satan bir mağazanın gerçekten sormak istediği budur:

if exports.mic_phone:RemoveCrypto(src, 'omen', price) then giveThem(thing) end

Cüzdan karaktere veya telefona aittir ve bu Config.Apps.Crypto.Wallet ayarıdır. Cihaz modunda bir telefonu çalmak portföyü de beraberinde çalar; karakter modunda çalınan bir telefon hırsıza boş bir uygulama gösterir. Export’lar her iki durumda da bir source alır ve hangisi olduğunu bilmeleri gerekmez.

Konsoldaki phonecrypto piyasayı yazdırır, phonecrypto <id> o oyuncunun neye sahip olduğunu yazdırır ve phonecrypto price <coin> <money> fiyatı elle oynatır.

İkisi de config’den açılır veya kapatılır — shared/config/battery.lua ve Config.Flashlight — ve ikisi de varsayılan olarak batarya için kapalı, el feneri için açıktır.

exports.mic_phone:BatteryLevel(src) --> 0-100, or 100 when the battery is switched off
exports.mic_phone:IsPhoneCharging(src)
exports.mic_phone:ChargePhone(src, true) -- plug in; false unplugs

Bir şarj aleti cepteki bir eşya olmak zorunda değildir. Config.Battery.Charger.Item kutudan çıktığı gibi size bir tane verir ve ChargePhone diğer her şey içindir: bir arabadaki kablo, duvardaki bir priz, bir masanın arkasındaki bir prop.

phonebattery [charge|unplug|full|empty] <id> onu oynatır; bu, sabrınızı test etmeden bir bataryayı test etmenin yoludur.

Oyundaki yöneticilerin (ve konsolun) bir şeyin neden istediğiniz gibi çalışmadığını bulmak için birkaç komutu vardır. Yalnızca bakarlar ya da bir oyuncunun telefonunu bilerek değiştirirler; hiçbiri bir şey uydurmaz.

phoneapi <id>bir oyuncu için state bag’ler, export’lar ve batarya
phoneappsconfig’in çözümlediği haliyle uygulama listesi
phonedevice [backup|restore] <id>hangi telefonu tuttukları ve sakladıkları kopyalar
phonebattery [charge|unplug|full|empty] <id>

phoneapi ayrıca o telefonda sinyal olup olmadığını ve onun için neyin bekletildiğini de yazdırır; bu, “sinyal yok”tan “bildirim geldi”ye giden zinciri iki satırda verir. Dört yerden geçer ve hangisinin yanlış gittiğini görmenin bir yolu yoktu.

Seviye bir zamanlayıcı değildir. Bir satır nerede olduğunu, ne zaman olduğunu ve telefonun ne yaptığını — açık, cepte veya şarjda — hatırlar ve şimdiki seviye saat üzerinde bir aritmetiktir. Yüz oyuncu yüz zamanlayıcıya değil, yüz sayıya mal olur ve bir sunucu yeniden başlatması boyunca şarjda bırakılan bir telefon donmuş olarak değil, şarj olmuş olarak geri gelir.

İstemlerinizi birinin fotoğraf albümünün dışında tutmak

Section titled “İstemlerinizi birinin fotoğraf albümünün dışında tutmak”

(Bu ve birlikte yaşamanın geri kalanı — ped, prop, eşya modu — kaynağınız onun yanında sayfasında toplanmıştır.)

Bir fotoğraf, çerçevenin tamamıdır. Deklanşöre basıldığı anda kaynağınızın çizdiği her şey — bir yardım istemi, bir marker etiketi, bir ilerleme çubuğu — fotoğrafın içindedir ve bu kaynak onu çizmenizi engelleyemez.

phoneCamera kendinizi durdurabilmeniz için vardır. Vizör açıldığı andan kapandığı ana kadar true’dur ve bir çizim döngüsündeki tek bir satır çözümün tamamıdır:

if LocalPlayer.state.phoneCamera then goto skip end

Telefonun kendi HUD’u zaten yoldan çekilmiştir: Config.Apps.Camera.HideHud, kamera açık kaldığı sürece oyunun mini haritasını ve can çubuklarını gizler; böylece birinin çerçevelediği şey, aldığı şeydir.

El feneri bir flashlight state bag’idir; dolayısıyla diğer her client ışını o oyuncunun ped’i üzerinde çizer. Yalnızca telefon dışarıdayken parlar ve telefon gidince söner.

exports.mic_phone:Open() / Close() / Toggle() / IsOpen()
exports.mic_phone:CanOpen() --> ok, reason
exports.mic_phone:Restricted() --> 'Dead' | 'Cuffed' | 'Swimming' | … | nil
exports.mic_phone:OpenApp('bank') / CloseApp()
exports.mic_phone:GetNumber() / GetDevice() / HasPhone() / IsBooted()
exports.mic_phone:IsInCall() / IsTablet() / SetTablet(true)
exports.mic_phone:Notify({ app =, title =, body = })

Buradaki hiçbir şey telefonun kendine uyguladığı kontrollerin ötesine geçmez. Open ve OpenApp, F1’e basan bir oyuncunun alacağı aynı reddi aynı nedenlerle alır — sahibi ölüyken bir kaynak kibarca istedi diye açılan bir telefon, kuralları olan bir telefon değildir. CanOpen ve Restricted, sormadan önce sorabilmeniz ve hiçbir şey yapmayan bir düğme sunmak yerine bir düğmeyi grileştirebilmeniz için vardır.

Anlam aynı olduğunda bag adları lb-phone’unkilerle eşleşir; böylece o telefona karşı yazılmış bir script bunu değişiklik yapmadan okur.