৩২-ওয়াগন ট্রেনের বিশাল একটা স্টেশন সামলানো মানে প্রায় ১২৮টা চেস্ট ম্যানেজ করা। আগে যেটা করতাম তাকে বলতাম "শিফট-ক্লিক ড্যান্স"—শিফট আর রাইট ক্লিক দিয়ে ইনসার্টার কপি করে শিফট আর লেফট ক্লিক দিয়ে ১২৮ বার পেস্ট করা। সময় লাগতো প্রচুর, আর ভুল হওয়ার সম্ভাবনাও ছিল বেশি।

Factorio Silo - A massive 32-wagon train docking at a high-speed loading station

ঝামেলাটা হলো, ১২৮টার মধ্যে জাস্ট একটা ইনসার্টার মিস করলে পুরো স্টেশনের ব্যালেন্স নষ্ট হয়ে যায়। একটা চেস্ট বেশি ফিল হয়ে যায়, ট্রেন লোড বা আনলোড হতে দেরি হয়। পুরো প্রোডাকশন লাইন স্থবির হয়ে যেতে পারে। আমি যখন দেখলাম নিজের হাতের উপর ভরসা করতে পারছি না, তখনই সিদ্ধান্ত নিলাম একটা Factorio Mod লিখে ফেলার।

GUI এর সেই ১৯৯০ দশকের স্বাদ

ভেবেছিলাম Factorio-এর Lua API হয়তো বেশ মডার্ন হবে। কিন্তু আমি মারাত্মক ভুল ছিলাম। এর GUI API অনেকটা ১৯৯০ দশকের ডেস্কটপ অ্যাপ ডেভেলপমেন্টের মতো—ম্যানুয়ালি প্রতিটি সুইচবোর্ড তার দিয়ে জোড়া দেওয়ার মতো অবস্থা। একটা স্লাইডার আর টেক্সট বক্স সিঙ্ক করতে চাইলে দুটোর জন্যই আলাদা আলাদা ইভেন্ট হ্যান্ডলার লিখতে হয়।

-- স্লাইডার আর টেক্সট বক্স সিঙ্ক রাখা বেশ যন্ত্রণার কাজ
if element.name == "issm_slider" then
    M.gui.elements.textfield.text = tostring(element.slider_value)
end-- স্লাইডার আর টেক্সট বক্স সিঙ্ক রাখা বেশ যন্ত্রণার কাজ
if element.name == "issm_slider" then
    M.gui.elements.textfield.text = tostring(element.slider_value)
end

মডের লজিক লিখতে যে সময় দিয়েছি, তার চেয়ে বেশি সময় ব্যয় করেছি on_gui_value_changed এর সাথে যুদ্ধ করতে।

ব্যাচ আপডেট এবং আমার মুক্তি

আমার বানানো এই Factorio Mod এর সবচেয়ে স্যাটিসফায়িং পার্ট হলো গ্রিন বক্স ড্র্যাগ করা। এক সেকেন্ডের মধ্যে ১২৮টা ইনসার্টার একদম নিখুঁত স্ট্যাক সাইজে সেট হয়ে যায়। Factorio এখন আর একঘেয়ে খাটুনির গেম মনে হয় না, বরং ইঞ্জিনিয়ারিং টুল মনে হয়।

এটির জন্য selection-tool ব্যবহার করেছি। ইঞ্জিন নিজেই আমাকে সিলেক্ট করা এরিয়ার ভেতর সব Entity এর টেবিল দিয়ে দেয়। আমি শুধু ফিল্টার করে দেখি কোনটা ইনসার্টার। ১০ মিনিটের যন্ত্রণাদায়ক ক্লিকিং ম্যারাথন এখন হাফ-সেকেন্ডের ব্যাচ আপডেটে পরিণত হয়েছে।

ইনভেন্টরি ফুল হলে যা ঘটে

মডটা ইউজেবল করার জন্য একটা কুইক গ্র্যাব হটকি যোগ করেছিলাম যা player.clear_cursor() কল করে। কিন্তু একটা মজার (আসলে বিরক্তিকর) জিনিস খেয়াল করলাম—যদি প্লেয়ারের ইনভেন্টরি ফুল থাকে, তবে clear_cursor() একদম নিরবে ফেইল করে! কোনো এরর মেসেজ দেয় না, মড ক্রাশও করে না, শুধু কোনো কাজই হয় না। প্রথমে ভেবেছিলাম কোডে কোনো বাগ আছে, পরে বুঝলাম এটা গেম ইঞ্জিনের সীমাবদ্ধতা। এখনো এর কোনো ভালো সলিউশন খুঁজে পাইনি।

মেগাবেস (Megabase) সামলানোর শখ থাকলে ছোটখাটো কিছু মড আসলে লাইফসেভার হতে পারে। এই প্রথম মড থেকে যে শিক্ষা নিয়েছি, তা পরবর্তীতে আরও জটিল প্রজেক্টে কাজে লাগবে।