จะใช้โลกทดสอบที่ไม่ต้องรีบูตได้อย่างไร


23

กำลังมองหาแนวคิดในการทำสิ่งต่อไปนี้: ฉันต้องการเขียน "โลก" อย่างง่ายใน Java หนึ่งที่ฉันสามารถเริ่มต้นแล้วเพิ่มวัตถุใหม่ในภายหลังในภายหลังเพื่อจำลอง / สังเกตพฤติกรรมที่แตกต่างระหว่างวัตถุที่มีอยู่ แผนการนั้นคือการเขียนโค้ดของวัตถุที่ใหม่กว่าหลังจากดูวัตถุเก่าในขณะนั้นจากนั้นโหลด / วางวัตถุเหล่านั้นในโลกที่มีอยู่ ปัญหาคือฉันไม่ต้องการหยุดหรือเริ่มโลกใหม่เมื่อเริ่มต้นฉันต้องการให้ทำงานสองสามสัปดาห์ แต่ฉันต้องการความสามารถในการวางวัตถุและทำซ้ำ / เขียนใหม่ / ลบ / สร้าง / กลายพันธุ์ เมื่อเวลาผ่านไปโดยไม่จำเป็นต้องรีบูต โลกอาจเป็นเรื่องง่ายเหมือนอาร์เรย์ 100 x 100 ของตำแหน่ง X / Y พร้อม GUI แบบเรียงต่อกันที่เป็นไปได้ที่จะเป็นตัวแทนของโลก ฉันรู้ว่าฉันต้องการกระบวนการ ticktimer เพื่อติดตามวัตถุและให้โอกาสในการกระทำ

ตัวอย่าง: ฉันโค้ด World.java ในวันจันทร์และปล่อยให้มันทำงานอยู่ จากนั้นในวันอังคารที่ฉันเขียนคลาสใหม่ที่เรียกว่า Rock.java (ที่ไม่ย้าย) จากนั้นฉันก็โหลด / วางมัน (อย่างใด?) ในโลกที่กำลังดำเนินอยู่นี้ (ซึ่งมันจะวางสุ่มลงไปในแถวลำดับโลกและไม่ย้าย) จากนั้นในวันพุธที่ฉันสร้างคลาสใหม่ที่เรียกว่า Cat.java และวางลงในโลกที่วางแบบสุ่มอีกครั้ง แต่วัตถุใหม่นี้สามารถย้ายไปทั่วโลก (ในบางหน่วยเวลา) จากนั้นในวันพฤหัสบดีที่ฉันเขียนชั้นเรียนที่เรียกว่าสุนัข java ซึ่งเคลื่อนที่ไปมา แต่สามารถ 'กระทำ' กับวัตถุอื่นได้หากอยู่ในตำแหน่งเพื่อนบ้านและในทางกลับกัน

นี่คือสิ่งที่ ฉันไม่รู้โครงสร้าง / การออกแบบชนิดใดฉันจะต้องเขียนรหัสระดับโลกจริงเพื่อทราบวิธีตรวจจับ / โหลด / ติดตามวัตถุในอนาคต (และปัจจุบันไม่มีอยู่)

มีความคิดเห็นเกี่ยวกับวิธีการทำสิ่งนี้โดยใช้ Java


2
เสียงมากเช่นการแลกเปลี่ยนความร้อน อาจมีวรรณกรรมบางอย่างเกี่ยวกับเรื่องนี้ที่อาจเป็นประโยชน์ อย่างไรก็ตามคำถามที่น่าสนใจมาก +1 …
Konrad Rudolph

คำตอบ:


5

สิ่งที่คุณกำลังมองหาคือระบบที่เสียบปลั๊กได้ คุณเรียกใช้แอปพลิเคชันหลักแล้วเพิ่มปลั๊กอินเมื่อรันไทม์ที่รวมอยู่ในลูปเหตุการณ์ ก่อนอื่นให้เริ่มคิดเกี่ยวกับสิ่งที่โลกคาดหวังจากเอนทิตีเกม ตัวอย่างเช่น (ขึ้นอยู่กับคำอธิบายของคุณ):

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
}

แน่นอนคุณสามารถเพิ่มวิธีอื่นที่คุณเห็นว่าจำเป็น หมายเหตุพารามิเตอร์โลกด้วยสองวิธีที่เกี่ยวข้อง สิ่งนี้จะช่วยให้เอนทิตีใหม่ของคุณพิจารณาโลกเมื่อทำการตั้งค่าหรืออัพเดท ยกตัวอย่างเช่นในชั้นเรียนสุนัขของคุณคุณสามารถถามแมวทุกตัวในพื้นที่ใกล้เคียงได้ ถัดไปคุณสร้างโลกของคุณที่ทำงานกับอินเทอร์เฟซนี้และระบบสำหรับการรวบรวมและการโหลดโค้ด Java แบบไดนามิก ตัวอย่างนี้สามารถพบได้ที่นี่

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

เรียกวิธีนี้จาก World GUI เพื่อเพิ่มเอนทิตีใหม่ ฟังก์ชั่นเริ่มต้นของเอนทิตีอาจมีลักษณะเช่นนี้ขึ้นอยู่กับการใช้งานโลกของคุณ:

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);
}

1
คำหลักไปยัง google: "IoC container", "Inversion of control", "การพึ่งพาการฉีด" เหล่านี้เป็นเทคนิคสำหรับระบบ hot-pluggable ทั่วไปที่สามารถค้นพบและโหลดคอมโพเนนต์ที่รันไทม์
ไม่เป็นไร

16

เราทำอะไรแบบนั้นในสเตนดาห์ลเพื่อการบุก

เราไม่ได้ตั้งเป้าที่จะหลีกเลี่ยงการรีสตาร์ทอย่างสมบูรณ์ ดังนั้นการเปลี่ยนแปลงบริการโครงสร้างพื้นฐานหลักของเราเช่นการสื่อสารกับไคลเอนต์ / เซิร์ฟเวอร์จึงจำเป็นต้องรีสตาร์ท แต่การเพิ่มเอนทิตีสิ่งมีชีวิตและ NPC และการแก้ไขวัตถุที่มีอยู่จะทำงานได้ (โอ้และบางครั้งการแก้ไขบั๊กแบบสดสามารถใช้การสะท้อนเพื่อจัดการกับฟิลด์ส่วนตัวได้)

เนื่องจากเราไม่เพียงต้องการวัตถุใหม่ที่อ้างอิงข้อมูลใหม่ (เช่นสกินอื่น) แต่ต้องการเพิ่มลักษณะการทำงานใหม่โปรแกรมโลกจึงจำเป็นต้องสามารถโหลดไฟล์คลาสใหม่ได้ เราเรียกมันว่า "สคริปต์" แต่มันเป็นคลาส Java จริงที่คอมไพล์แล้ว คลาสเหล่านั้นใช้อินเตอร์เฟสScript.java

Maria.javaเป็นตัวอย่างง่ายๆ เธอเป็น NPC ใหม่ที่ขายเครื่องดื่มและอาหารให้ผู้เล่น เราสามารถกำหนดวัตถุที่ซับซ้อนมากในนั้นเช่นกัน

คลาสใหม่ถูกโหลดด้วยวิธีนี้:

// 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();

หากคุณสามารถตรวจสอบชื่อที่ไม่ซ้ำและไม่ต้องการยกเลิกการโหลดคลาสคุณจะทำสิ่งต่าง ๆ ในระดับต่ำ

อย่างไรก็ตามการขนถ่ายดูเหมือนว่าสำคัญทีเดียว เพื่อให้บรรลุผลนั้นคุณต้องสร้างอินสแตนซ์คลาสโหลดเดอร์ใหม่ทุกครั้งที่คุณต้องการฉีดโค้ดใหม่ เพื่อให้ GC สามารถทำงานได้หลังจากการอ้างอิงล่าสุดไปยังรหัสนั้นถูกล้าง

เรามีคำสั่ง / unloadที่เรียกใช้เมธอด unload ในอินเทอร์เฟซของเราเพื่อให้สคริปต์สามารถล้างข้อมูลได้ การขนถ่ายจริงจะดำเนินการโดยอัตโนมัติโดย GC

เรามักสร้างวัตถุชั่วคราวจำนวนมากในระหว่างการตรวจค้น และเราต้องการให้พวกเขาทั้งหมดถูกลบออกหลังจากการโจมตีสิ้นสุดลง ตัวอย่างเช่นการโจมตีพวกโนมส์ซึ่ง spawns จำนวนของโนมส์ใกล้ admin ที่มองไม่เห็นเราใช้รหัสนี้GnomeRaid.javaขยายCreateRaid.java

สคริปต์สามารถเข้าถึงโลกได้โดยตรง (ตามตัวอย่างแรกแสดง) และทำความสะอาดตัวเองในเมธอด unload () แต่ตัวแปลงสัญญาณ Java ไม่ได้ใช้เพื่อทำความสะอาดและเป็นที่น่ารำคาญ ดังนั้นเราจึงสร้างSandboxที่สคริปต์อาจใช้ ในการยกเลิกการโหลดวัตถุทั้งหมดที่ถูกเพิ่มไปยังโลกผ่านคลาส Sandbox จะถูกลบออก


3

ช่วยโลก (ไม่ได้ตั้งใจเล่นสำนวน) และรัฐทั้งหมดของมัน (ตำแหน่ง, ความเร็ว, ตัวแปรทั้งหมด)

  • ปิดโปรแกรม
  • ใช้การเปลี่ยนแปลง (รับรองความเข้ากันได้ย้อนหลังกับบันทึก)
  • คอมไพล์โปรแกรมใหม่
  • เริ่มโปรแกรมใหม่
  • โหลดโลกและรัฐ
  • ทำซ้ำ

นี่เป็นวิธีการแก้ปัญหาทั่วไป แต่ฉันไม่ได้เจาะจง Java ให้ทราบว่าคุณสามารถใช้บล็อคโค้ดและคลาสแบบไดนามิกเช่นเดียวกับที่คุณหวัง ...

ตัวเลือกที่ 2คือการผูกภาษาสคริปต์ที่สามารถโหลดได้ทันที


+1 สำหรับภาษาสคริปต์ หากคุณไม่ได้ผูกพันกับ Java ลองใช้ไดรเวอร์และโคลน MUD ที่ใช้ LPC บางส่วนเช่นกัน
Martin Sojka

1

สำหรับ Java ทั้งหมดที่คุณต้องเป็นแพลตฟอร์ม OSGi เนื่องจากเป็นโมดูลหรือแอปพลิเคชั่น hot-swap เล็ก ๆ น้อย ๆ และแม้แต่การจัดการระยะไกลหรือการอัพเกรดบางส่วน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.