Bagaimana cara menerapkan dunia pengujian yang tidak pernah reboot?

23

Saya sedang mencari ide tentang bagaimana melakukan hal berikut: Saya ingin menulis "dunia" sederhana di Jawa. Yang saya bisa mulai dan kemudian menambahkan objek baru di kemudian hari untuk mensimulasikan / mengamati perilaku yang berbeda antara objek yang ada. Rencananya adalah untuk membuat kode objek yang lebih baru setelah menonton yang lama untuk sementara dan kemudian memuat / menjatuhkannya ke dunia yang ada. Masalahnya adalah bahwa saya tidak ingin menghentikan atau memulai kembali dunia setelah dimulai, saya ingin menjalankannya selama beberapa minggu, tetapi saya memang membutuhkan kemampuan untuk menjatuhkan objek dan mengulang / menulis ulang / menghapus / membuat / mengubah mereka dari waktu ke waktu tanpa perlu reboot. Dunia bisa sesederhana array 100 x 100 lokasi X / Y, dengan GUI peta keramik yang mungkin untuk secara visual mewakili dunia. Saya tahu saya perlu semacam proses ticktimer untuk memantau objek dan memberikan masing-masing 'kesempatan untuk bertindak'

Contoh: Saya membuat kode World.java pada hari Senin dan membiarkannya tetap berjalan. Kemudian pada hari Selasa saya menulis kelas baru yang disebut Rock.java (itu tidak bergerak). Saya kemudian memuat / menjatuhkannya (entah bagaimana?) Ke dunia yang sudah berjalan ini (yang hanya menjatuhkannya ke suatu tempat acak dalam array dunia dan tidak pernah bergerak). Kemudian pada hari Rabu saya membuat kelas baru bernama Cat.java dan menjatuhkannya ke dunia, sekali lagi ditempatkan secara acak, tetapi objek baru ini dapat bergerak di seluruh dunia (dalam beberapa satuan waktu), kemudian pada hari Kamis saya menulis kelas yang disebut Dog. java yang juga bergerak tetapi dapat 'beraksi' pada objek lain jika berada di lokasi tetangga dan sebaliknya.

Ini masalahnya. Saya tidak tahu seperti apa struktur / desain yang saya perlukan untuk mengkodekan kelas dunia yang sebenarnya untuk mengetahui cara mendeteksi / memuat / melacak objek di masa depan (dan saat ini tidak ada).

Ada ide tentang bagaimana Anda akan melakukan sesuatu seperti ini menggunakan Java?

d33j
sumber
2
Kedengarannya seperti pertukaran panas . Mungkin ada beberapa literatur tentang ini yang dapat membantu. Pokoknya, pertanyaan yang sangat menarik. +1 ...
Konrad Rudolph

Jawaban:

5

Apa yang Anda cari pada dasarnya adalah sistem hot-pluggable. Anda menjalankan aplikasi utama dan kemudian menambahkan plug-in saat runtime yang terintegrasi dalam loop acara. Pertama, mulailah berpikir tentang apa yang diharapkan dunia Anda dari entitas game. Misalnya (berdasarkan uraian Anda):

interface Entity {
   void init(World world);
   // Called when loaded for the first time in the world and adds itself
   // to the world (correct position in the array, scheduler for updates)

   void update(World world);
   // Called when scheduler fires (allows the entity to think about its
   // next move)

   Image getImage();
   // Called by the GUI when it is time to draw the entity on the screen
}

Tentu saja, Anda dapat menambahkan metode lain yang Anda anggap perlu. Perhatikan parameter Dunia dengan dua metode yang relevan. Ini memungkinkan entitas baru Anda mempertimbangkan dunia saat menyiapkan atau memperbarui. Di kelas Anjing Anda, misalnya, Anda dapat meminta dunia untuk semua kucing di lingkungan tersebut. Selanjutnya, Anda menciptakan dunia Anda yang berfungsi dengan antarmuka ini dan sistem untuk kompilasi dan pemuatan kode Java secara dinamis. Contoh dari ini dapat ditemukan di sini .

void injectEntity(String filename, World world) {
    // Load the class as described in the mentioned link
    Entity e = (Entity) loadClass(filename);
    e.init(world);
}

Panggil metode ini dari GUI Dunia untuk menambahkan entitas baru. Bergantung pada implementasi Dunia Anda, fungsi entitas Entitas dapat terlihat seperti ini:

void init(World world) {
   // Register entity with world for easy access
   world.register(this, "RockImpl A");

   // Place the entity on the world map
   Point initialLocation = Point(10,5);
   world.place(this, initialLocation);

   // Schedule its update method for every 5 seconds
   world.schedule(this, 5);
}
hantu
sumber
1
Kata kunci ke google: "Kontainer IoC", "Inversi kontrol", "Injeksi ketergantungan". Ini adalah teknik untuk sistem hot-pluggable generik, yang dapat menemukan dan memuat komponen saat runtime.
Nevermind
16

Kami melakukan sesuatu seperti itu di Stendhal untuk penggerebekan.

Kami tidak bertujuan untuk sepenuhnya menghindari memulai kembali. Jadi perubahan pada layanan infrastruktur inti kami seperti komunikasi klien / server memang perlu dimulai ulang. Tetapi menambahkan entitas, makhluk dan NPC, dan memodifikasi objek yang ada berhasil. (Oh, dan terkadang perbaikan bug langsung, refleksi dapat digunakan untuk memanipulasi bahkan bidang pribadi).

Karena kita tidak hanya menginginkan objek baru berdasarkan data baru (seperti skin lain), tetapi ingin menambahkan perilaku baru, program dunia harus dapat memuat file kelas baru . Kami menyebutnya "skrip", tetapi mereka sebenarnya adalah kelas Java yang dikompilasi. Kelas-kelas tersebut mengimplementasikan antarmuka Script.java .

Maria.java adalah contoh sederhana. Dia adalah NPC baru yang menjual minuman dan makanan kepada pemain. Kita dapat mendefinisikan objek yang sangat kompleks di sana juga.

Kelas baru dimuat dengan cara ini:

// create a new class loader, with the script folder as classpath.
final File file = new File("./data/script");
final ClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()});

// load class through new loader
final Class< ? > aClass = loader.loadClass(classname);
script = (Script) aClass.newInstance();

Jika Anda dapat memastikan nama-nama unik dan tidak pernah ingin menurunkan kelas, Anda selesai dengan hal-hal tingkat rendah.

Namun, bongkar muat tampaknya cukup penting. Untuk mencapai itu, Anda harus instantiate loader kelas baru setiap kali Anda ingin menyuntikkan kode baru. Sehingga GC dapat melakukan tugasnya setelah referensi terakhir ke kode itu dihapus.

Kami memiliki perintah / unload yang memanggil metode unload di antarmuka kami sehingga skrip dapat melakukan pembersihan. Bongkar nyata dilakukan secara otomatis oleh GC.

Kami sering membuat banyak objek sementara selama penggerebekan. Dan kami ingin semuanya dihapus setelah serangan berakhir. Misalnya Gnome Raid, yang memunculkan sejumlah gnome di dekat admin yang tidak terlihat, kami menggunakan kode ini: GnomeRaid.java meluas CreateRaid.java .

Script dapat mengakses dunia secara langsung (seperti yang ditunjukkan contoh pertama) dan melakukan pembersihan sendiri dalam metode unload (). Tapi Java coders tidak digunakan untuk melakukan pembersihan, dan itu menjengkelkan. Jadi kami membuat kotak pasir yang dapat digunakan skrip. Saat membongkar semua objek yang ditambahkan ke dunia melalui kelas Sandbox dihapus.

Hendrik Brummermann
sumber
3

Simpan dunia (tidak ada permainan kata pun) dan semua statusnya (posisi, kecepatan, semua variabel).

  • Tutup programnya.
  • Terapkan perubahan (memastikan kompatibilitas ke belakang dengan simpanan).
  • Kompilasi ulang program.
  • Mulai ulang program.
  • Memuat dunia dan negara.
  • Ulangi

Ini adalah solusi umum, saya tidak spesifik Java untuk mengetahui apakah Anda dapat secara dinamis mengimplementasikan blok kode dan kelas seperti yang Anda harapkan ...

Opsi 2 , adalah untuk mengikat bahasa skrip yang dapat dimuat dengan cepat.

kaviar melambat
sumber
+1 untuk bahasa skrip. Jika Anda tidak terikat dengan Java, cobalah beberapa driver MUD dan mudlibs berbasis LPC juga.
Martin Sojka
1

Untuk Java, yang Anda butuhkan adalah platform OSGi . Dengan itu sepele untuk hot-swap modul atau aplikasi, dan bahkan melakukan manajemen jarak jauh atau peningkatan parsial.


sumber