Làm thế nào để thực hiện một thế giới thử nghiệm không bao giờ khởi động lại?


23

Đang tìm kiếm ý tưởng về cách thực hiện như sau: Tôi muốn viết một "thế giới" đơn giản bằng Java. Một trong đó tôi có thể bắt đầu và sau đó thêm các đối tượng mới vào một ngày sau đó để mô phỏng / quan sát các hành vi khác nhau giữa các đối tượng hiện có. Kế hoạch sau đó là mã hóa các đối tượng mới hơn sau khi xem các đối tượng cũ một lúc rồi tải / thả chúng vào thế giới hiện có. Vấn đề là tôi không muốn dừng lại hoặc khởi động lại thế giới khi nó bắt đầu, tôi muốn nó chạy trong vài tuần nhưng tôi cần khả năng thả vào các đối tượng và làm lại / viết lại / xóa / tạo / biến đổi chúng theo thời gian mà không cần khởi động lại. Thế giới có thể đơn giản như một mảng 100 x 100 vị trí X / Y, với GUI có bản đồ được lát gạch có thể để thể hiện trực quan thế giới. Tôi biết tôi cần một số quy trình đánh dấu để theo dõi các đối tượng và cho mỗi người một 'cơ hội để hành động'

Ví dụ: Tôi mã hóa World.java vào thứ Hai và để nó chạy. Sau đó vào thứ ba, tôi viết một lớp mới gọi là Rock.java (không di chuyển). Sau đó tôi tải / thả nó (bằng cách nào đó?) Vào thế giới đã chạy này (chỉ cần thả nó ở một nơi nào đó ngẫu nhiên trong mảng thế giới và không bao giờ di chuyển). Sau đó vào thứ Tư, tôi tạo một lớp mới gọi là Cat.java và thả nó vào thế giới, một lần nữa được đặt ngẫu nhiên, nhưng đối tượng mới này có thể di chuyển khắp thế giới (qua một số đơn vị thời gian), sau đó vào thứ năm tôi viết một lớp có tên là Dog. java cũng di chuyển xung quanh nhưng có thể 'hành động' trên một đối tượng khác nếu nó ở vị trí lân cận và ngược lại.

Vấn đề là như thế này. Tôi không biết loại cấu trúc / thiết kế nào tôi sẽ cần mã hóa lớp thế giới thực để biết cách phát hiện / tải / theo dõi các đối tượng trong tương lai (và hiện không tồn tại).

Có ý tưởng nào về cách bạn sẽ làm một cái gì đó như thế này bằng cách sử dụng Java không?


2
Âm thanh rất giống như trao đổi nóng . Có lẽ có một số tài liệu về điều này có thể hữu ích. Dù sao, câu hỏi rất thú vị. +1 Voi
Konrad Rudolph

Câu trả lời:


5

Những gì bạn đang tìm kiếm về cơ bản là một hệ thống cắm nóng. Bạn chạy một ứng dụng chính và sau đó thêm các trình cắm trong thời gian chạy được tích hợp trong vòng lặp sự kiện. Đầu tiên, bắt đầu suy nghĩ về những gì thế giới của bạn mong đợi từ một thực thể trò chơi. Ví dụ (dựa trên mô tả của bạn):

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
}

Tất nhiên, bạn có thể thêm các phương pháp khác mà bạn thấy cần thiết. Lưu ý tham số World với hai phương thức liên quan. Điều này cho phép thực thể mới của bạn xem xét thế giới khi thiết lập hoặc cập nhật. Ví dụ, trong lớp Dog của bạn, bạn có thể hỏi thế giới về tất cả những con mèo trong khu phố. Tiếp theo, bạn tạo thế giới của mình hoạt động với giao diện này và một hệ thống để tự động biên dịch và tải mã Java. Một ví dụ về điều này có thể được tìm thấy ở đây .

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

Gọi phương thức này từ GUI thế giới để thêm các thực thể mới. Tùy thuộc vào việc triển khai Thế giới của bạn, một hàm init Entity có thể trông như thế này:

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
Từ khóa cho google: "Container IoC", "Đảo ngược kiểm soát", "Tiêm phụ thuộc". Đây là các kỹ thuật cho các hệ thống có thể cắm nóng chung, có thể khám phá và tải các thành phần khi chạy.
Nevermind

16

Chúng tôi đã làm một cái gì đó như thế trong Stendhal cho các cuộc đột kích.

Chúng tôi không nhằm mục đích hoàn toàn tránh khởi động lại. Vì vậy, những thay đổi đối với các dịch vụ cơ sở hạ tầng cốt lõi của chúng tôi như giao tiếp máy khách / máy chủ cần phải khởi động lại. Nhưng việc thêm các thực thể, sinh vật và NPC và sửa đổi các đối tượng hiện có sẽ hoạt động. (Ồ, và đôi khi sửa lỗi trực tiếp, phản xạ có thể được sử dụng để thao tác ngay cả các trường riêng tư).

Vì chúng tôi không chỉ muốn đối tượng mới dựa trên dữ liệu mới (như giao diện khác) mà còn muốn thêm hành vi mới, chương trình thế giới cần có khả năng tải các tệp lớp mới . Chúng tôi gọi chúng là "các tập lệnh", nhưng chúng là các lớp Java được biên dịch thực sự. Các lớp này thực hiện giao diện Script.java .

Maria.java là một ví dụ đơn giản. Cô là một NPC mới bán đồ uống và thức ăn cho người chơi. Chúng ta cũng có thể định nghĩa các đối tượng rất phức tạp trong đó.

Một lớp mới được tải theo cách này:

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

Nếu bạn có thể đảm bảo tên duy nhất và không bao giờ muốn hủy tải các lớp, bạn đã hoàn thành công cụ cấp thấp.

Dỡ bỏ , tuy nhiên, có vẻ khá quan trọng. Để đạt được điều đó, bạn phải khởi tạo trình nạp lớp mới bất cứ khi nào bạn muốn tiêm mã mới. Vì vậy, GC có thể thực hiện công việc của nó sau khi tham chiếu cuối cùng đến mã đó bị xóa.

Chúng tôi có một lệnh / unload gọi một phương thức unload trong giao diện của chúng tôi để các script có thể thực hiện dọn dẹp. Việc dỡ tải thực sự được thực hiện tự động bởi GC.

Chúng tôi thường tạo ra nhiều đối tượng tạm thời trong các cuộc đột kích. Và chúng tôi muốn tất cả chúng sẽ được gỡ bỏ sau khi cuộc đột kích kết thúc. Ví dụ: Gnomes Raid, sinh ra một số gnomes gần quản trị viên vô hình, chúng tôi sử dụng mã này: GnomeRaid.java mở rộng CreatRaid.java .

Kịch bản có thể truy cập trực tiếp vào thế giới (như ví dụ đầu tiên hiển thị) và tự dọn sạch trong phương thức unload (). Nhưng các lập trình viên Java không được sử dụng để dọn dẹp và điều đó thật khó chịu. Vì vậy, chúng tôi đã tạo ra một hộp cát mà các kịch bản có thể sử dụng. Khi dỡ tất cả các đối tượng được thêm vào thế giới thông qua lớp Sandbox sẽ bị xóa.


3

Cứu thế giới (không có ý định chơi chữ) và tất cả trạng thái của nó (vị trí, vận tốc, tất cả các biến).

  • Đóng chương trình.
  • Thực hiện các thay đổi (đảm bảo khả năng tương thích ngược với tiết kiệm).
  • Biên dịch lại chương trình.
  • Khởi động lại chương trình.
  • Tải thế giới và nhà nước.
  • Nói lại

Tuy nhiên, đây là một giải pháp chung, tôi không biết cụ thể về Java để biết liệu bạn có thể tự động triển khai các khối mã và các lớp như bạn hy vọng không ...

Tùy chọn 2 , là liên kết một ngôn ngữ kịch bản có thể được tải nhanh chóng.


+1 cho ngôn ngữ kịch bản. Nếu bạn không bị ràng buộc với Java, hãy thử một số trình điều khiển MUD và Mudlibs dựa trên LPC.
Martin Sojka

1

Đối với Java, tất cả những gì bạn cần là một nền tảng OSGi . Với điều đó, nó là tầm thường đối với các mô-đun hoặc ứng dụng trao đổi nóng, và thậm chí thực hiện quản lý từ xa hoặc nâng cấp một phần.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.