kindergarten writing paper pay someone to write my essay how to write a essay for college best essay writing service review how to write a rationale for an essay

Zone Instancing

  • Gahan
  • Topic Author
  • Offline
  • Junior Boarder
  • Junior Boarder
More
1 month 2 weeks ago #8626 by Gahan
Zone Instancing was created by Gahan
Hey folks, due to lock-down I have decided to get back into the grit, and add some new features to a mud. Currently, I am looking for folks who have either added zone instancing already into their mud or people with ideas on how to do it efficiently within the tbaMUD realm.

I have been able to create a new zone with the old zone's information and have been able to create new rooms, but I feel like this process is duplicating a lot of existing code, as the existing code doesn't really seem to support mass creation of content in-game. One of the things I've been able to manage doing it the long way, is not to have the data stored to disk. That way after a certain period of time the zone gets free'd or if the mud is rebooted so instanced zones don't "pile up".

Would like to start a discussion on it if anyone is interested!

Please Log in or Create an account to join the conversation.

More
1 month 2 weeks ago #8628 by thomas
Replied by thomas on topic Zone Instancing
I have some thoughts about this.

But first, some requirements gathering:

- When you say "zone instancing" are you thinking of randomized zones (like the mission zones in Anarchy Online) or more traditional "raid" instances?
- Do you want the option of having a group instance (so members of a group get back to the same instance if they reenter after a death).
- How do you want to handle deaths? I mean, if I drop all my items in the zone, and it despawns, do I lose all my stuff?
- What is the purpose? Avoiding kill-stealing? Scaling the mobs/rewards to fit the group?
- those zones - will they have zone reset events? Ie. are mobs going to respawn here?`

I'm sure this list isn't complete, but it's a start. A thing I've been working on lately at work is "user stories" as a way of requirements specification. These have the format
As a <role or person> I would like <thing to happen> so that <value proposition>.
The most important being the value proposition. With the questions above I'm trying to determine the value these instances will provide to the players or you as an implementor. My first guess is

As a player i would like instanced zones so that other players don't steal my loot.

I'm not entirely sure that's the real value - please help me out here.
The following user(s) said Thank You: Gahan

Please Log in or Create an account to join the conversation.

  • Gahan
  • Topic Author
  • Offline
  • Junior Boarder
  • Junior Boarder
More
1 month 2 weeks ago #8629 by Gahan
Replied by Gahan on topic Zone Instancing
When I say zone instancing i'm thinking about having a "source" zone and making an identical copy of it to my "instanced" zone, and adding an identifier to it so that it can be accessed by those who created it (without their knowledge). For sanity purposes I suppose I'd start by creating a new zone with a new zone number, different room vnums (incremented identically from the source zone) and then copy in all of the zone reset commands, leaving original mob vnums/obj vnums/shops/triggers to load properly.

I, ideally would start by adding a new groupID value to the group or player structure when a group is created so that I could identify those who were able to access the zone.

For deaths, our corpses don't populate with gear. However, that's a good point. If you "drop" items in the zone and it despawns then of course you would lose your stuff. The same way you would lose your stuff if you dropped stuff on the group and the mud was rebooted. My original plan would to have the zone reset despawn an instance after it was empty for a certain period of time. Say, 30 - 60 minutes. Which would probably solve the corpse issue, as they would decompose long before the zone despawns.

For the purpose of this, yes avoid kill-stealing, or interfering with special quests, the ability to scale mobs for large groups would definitely be one of top 5 reasons. My MUD has some player killing elements as well and this would allow for a period of time on certain missions in which they'd not have to worry about it. Also, I know "gear runners" in some muds are always the first to a zone to get the gear... for special quest related gear items this would allow everyone to have a fair crack and not be limited specifically to max_load or percent load. Which in my opinion is more interesting than a quest keeper just giving you the special dragon slayer sword that you would have gotten as loot for killing the epic dragon slayer himself. I could list other value propositions, but i think these are the main ones.

Yes, these zones would have zone reset events.

I'm not looking for anyone to do the work for me, in fact, I've kind of looked forward to this challenge for a while, but I am not anywhere near your league for knowledge in programming, so I thought I'd pop in here first and get everyone's 2 cents.

Appreciate the reply Thomas!

Please Log in or Create an account to join the conversation.

More
1 month 2 weeks ago #8631 by thomas
Replied by thomas on topic Zone Instancing
Now we know what you're trying to achieve, we can ask even deeper:

Would it be acceptable to have some kind of instance marker you could share? For instance, the questgiver (or whatever means we are using to distribute the quest) give a "token" of a sort that has an internal code?
Think of something like this:
The questmaster gives you a key to the dungeons.
> examine key
This is a key to the dungeons, given to playername. You can use it to enter your own dungeon.
If you need help, you can give a copy of the key to another player. They can then enter the same
dungeon. To do this, use the command: copy key to playername

The key has an ephemeral feeling.
The key seems to be fading from existence. It will be completely gone in 105 hours.
Here, the "ephemeral" would mean it persisted after death and that it disappears in a cloud of smoke if it is ever intentionally dropped or attempted rented. Attempts to give it away/steal it should fail.

I'm introducing some new concepts here - persistence across death, timed objects, a "copy" (and corresponding "accept") command.

All this to avoid assigning a specific id to a group and preventing changes to a group (or joining a group half-way through) from causing trouble. For instance, say I'm part of one group when I accept the quest, but join another before going into the instance - who should have access?

Also, having objects with a set timeout will help us in deciding whether a zone can be safely unloaded - no more access keys == no more zone. It could even go as far as when the zone has been "defeated", the key is removed from everyone, so the zone is no longer accessible. And once everyone has left, it is removed.

About the actual implementation: There are some limits that need to be addressed for this to work.
github.com/tbamud/tbamud/blob/master/src/structs.h#L24 :
/* preamble */
/** As of bpl20, it should be safe to use unsigned data types for the various
 * virtual and real number data types.  There really isn't a reason to use
 * signed anymore so use the unsigned types and get 65,535 objects instead of
 * 32,768. NOTE: This will likely be unconditionally unsigned later.
 * 0 = use signed indexes; 1 = use unsigned indexes */
#define CIRCLE_UNSIGNED_INDEX	1

#if CIRCLE_UNSIGNED_INDEX
# define IDXTYPE	ush_int          /**< Index types are unsigned short ints */
# define IDXTYPE_MAX USHRT_MAX     /**< Used for compatibility checks. */
# define IDXTYPE_MIN 0             /**< Used for compatibility checks. */
# define NOWHERE	((IDXTYPE)~0)    /**< Sets to ush_int_MAX, or 65,535 */
# define NOTHING	((IDXTYPE)~0)    /**< Sets to ush_int_MAX, or 65,535 */
# define NOBODY		((IDXTYPE)~0)    /**< Sets to ush_int_MAX, or 65,535 */
# define NOFLAG   ((IDXTYPE)~0)    /**< Sets to ush_int_MAX, or 65,535 */
#else
# define IDXTYPE	sh_int           /**< Index types are unsigned short ints */
# define IDXTYPE_MAX SHRT_MAX      /**< Used for compatibility checks. */
# define IDXTYPE_MIN SHRT_MIN      /**< Used for compatibility checks. */
# define NOWHERE	((IDXTYPE)-1)    /**< nil reference for rooms */
# define NOTHING	((IDXTYPE)-1)    /**< nil reference for objects */
# define NOBODY		((IDXTYPE)-1)	   /**< nil reference for mobiles  */
# define NOFLAG   ((IDXTYPE)-1)    /**< nil reference for flags   */
#endif
The limit is currently 65535 rooms in the world. In all zones, regardless of whether they're loaded dynamically. This makes it slightly more trouble to do this. For us to actually do this, we'll need a somewhat larger addressable scope, at least an uint32. i haven't tested tbamud with this, but it might be simple: os.mbed.com/handbook/C-Data-Types
Upping it to an uint32_t would let us use 4 million room, though this would potentially have an impact on the performance of other aspects of the mud. I think we can safely say that we need to look into this before just changing the limit (we're looping over "all rooms" and "all items" quite often).

Please Log in or Create an account to join the conversation.

  • Gahan
  • Topic Author
  • Offline
  • Junior Boarder
  • Junior Boarder
More
1 month 2 weeks ago #8632 by Gahan
Replied by Gahan on topic Zone Instancing
The key idea is definitely a feasible concept, however my original plan was to streamline it a bit more and have the actual zone linked lets say you're in room 199 and exit 200 is north but is flagged ZONE_INSTANCE or some such thing. A call would be made to create the duplicate zone in instance "space". (An allotted amount of potential vnums that haven't been loaded yet via #defined macros). Some integration of the #define MIN_INSTANCE / MAX_INSTANCE could take some of the looping pressure off the cpu couldn't it?

I have actually gone through the work of changing the IDXTYPE to u_int (my linux distro is 64-bit and thus has a size_of u_int of over 4 billion). It does create other obvious issues such as saving zon/wld/obj/mob/trg/shp data, because all of the routines use %d instead of %u (or in your 32 bit uint32 case %ul) to parse the vnums. Similarly the display issues arise with displaying original short int vnums with %d. After changing all of them (and btw there are a bunch the compiler doesn't pick up for whatever reason), I am able to create zones up to 40 million (change max_zone) and vnums up to 4 billion (nr>4000000 instead of 65535).

That said, my test tbaMUD has been stripped of all zones and i'm playing with limbo and zone 1, so I really cannot comment on how this has impacted performance, like, at all and likely can't until I've gone too far with this, lol!

As far as the development has gone on my end so far, I've been able to have a player walk into a normal zone with my new "INSTANCED" flag (or through a door, or entering a special door) the MUD identifies it and takes the "source" zone from the room the player is in, and loops from #MIN_INSTANCED_ZONE to where a zone doesn't exist, creates an empty zone, recreates the top_of_zone list, and then populates the struct zone_data with the the source zone. I have gone one step further to create a new room in that zone to test the seamless passage by removing them from their existing room and putting them into the new room in the new zone but this is where I am stuck, and re-thinking my implementation.

The code I started writing from cycling through each room in the source zone and the creation of the new zone is almost identical to existing code, but with fewer "features" IE: i dont want the zone to be saved to disk, etc.

Please Log in or Create an account to join the conversation.

More
1 month 1 week ago #8634 by thomas
Replied by thomas on topic Zone Instancing
Of course, 4 billion, don't know what I was thinking.

Given the requirements, I'd go ahead and "tag" each created zone with the player ID, and then when a player tries to enter, check if they're the same ID or if they're currently grouped with that player as the group leader.

This will make sure only people the original player want to see are coming along (or he'd kick them from the group) and also makes it quite easy to get back, without the need for specific objects persisting through death.
Also, it makes it easy to send a message when entering: "This instance is owned by Spiffer, your group leader", in case you want to send some message when it happens.

So, the next step - when you enter, you need to tag with the current players id.

Whenever any movement occurs, I'd check if the zone for the two rooms is the same - this is where I'd track if the zone is empty (so, you're the last player, and you've been killed? Ok, the zone is now empty). I think I'd also track "last command issued" here, in case I'd want to force remove the instance even if there's a player idling there.

The mechanism to actually copy the rooms is the same you see other places, in the OLC. To avoid having too many functions with the same purpose, they could probably be refactored a bit, but I don't think it's really that difficult, though care must be taken to free the memory correctly.

Please Log in or Create an account to join the conversation.

  • Gahan
  • Topic Author
  • Offline
  • Junior Boarder
  • Junior Boarder
More
1 month 1 week ago #8646 by Gahan
Replied by Gahan on topic Zone Instancing
Just for the record, I haven't abandoned the conversation. I appreciate your input a lot. That said, I decided to take your advice and try to use existing infrastructure to do the copying into the new instanced area. I'm having a difficult time though because oasis_copy is handled a little differently. I'm testing right now having the do_oasis_copy command called within my instancing code, but having difficulty with overriding arguments at the moment. Will update you guys soon with some code, and maybe you can tell me how badly I've hacked it up. Ha! Thanks again for the chat, thomas!
The following user(s) said Thank You: lacrc

Please Log in or Create an account to join the conversation.

More
2 weeks 2 days ago #8703 by cunning
Replied by cunning on topic Zone Instancing
I have this solved:
diff -ruN srcbak/db.c src/db.c
--- srcbak/db.c 2020-05-13 08:42:45.682527148 -0400
+++ src/db.c    2020-05-13 08:44:41.264195701 -0400
@@ -1155,9 +1155,7 @@
        log("SYSERR: Format error after %s #%d", modes[mode], last);
        exit(1);
       }
-      if (nr >= 99999)
-       return;
-      else
+
        switch (mode) {
        case DB_BOOT_WLD:
          parse_room(fl, nr);
@@ -2111,7 +2109,7 @@
 
   line_num += get_line(fl, buf);
 
-  if (sscanf(buf, "#%hd", &Z.number) != 1) {
+  if (sscanf(buf, "#%d", &Z.number) != 1) {
     log("SYSERR: Format error in %s, line %d", zname, line_num);
     exit(1);
   }
@@ -2134,15 +2132,15 @@
 
   line_num += get_line(fl, buf);
   /* Look for 10 items first (new tbaMUD), if not found, try 4 (old tbaMUD) */
-  if  (sscanf(buf, " %hd %hd %d %d %s %s %s %s %d %d", &Z.bot, &Z.top, &Z.lifespan,
+  if  (sscanf(buf, " %d %d %d %d %s %s %s %s %d %d", &Z.bot, &Z.top, &Z.lifespan,
       &Z.reset_mode, zbuf1, zbuf2, zbuf3, zbuf4, &Z.min_level, &Z.max_level) != 10)
   {
-    if (sscanf(buf, " %hd %hd %d %d ", &Z.bot, &Z.top, &Z.lifespan, &Z.reset_mode) != 4) {
+    if (sscanf(buf, " %d %d %d %d ", &Z.bot, &Z.top, &Z.lifespan, &Z.reset_mode) != 4) {
       /* This may be due to the fact that the zone has no builder.  So, we just
        * attempt to fix this by copying the previous 2 last reads into this
        * variable and the last one. */
       log("SYSERR: Format error in numeric constant line of %s, attempting to fix.", zname);
-      if (sscanf(Z.name, " %hd %hd %d %d ", &Z.bot, &Z.top, &Z.lifespan, &Z.reset_mode) != 4) {
+      if (sscanf(Z.name, " %d %d %d %d ", &Z.bot, &Z.top, &Z.lifespan, &Z.reset_mode) != 4) {
         log("SYSERR: Could not fix previous error, aborting game.");
         exit(1);
       } else {
diff -ruN srcbak/genzon.c src/genzon.c
--- srcbak/genzon.c     2020-05-13 08:42:45.686527205 -0400
+++ src/genzon.c        2020-05-13 08:51:03.565715679 -0400
@@ -51,22 +51,20 @@
 {
   FILE *fp;
   struct zone_data *zone;
-  int i, max_zone;
+  int i, max_zone = IDXTYPE_MAX / 100;
   zone_rnum rznum;
   char buf[MAX_STRING_LENGTH];
 
 #if CIRCLE_UNSIGNED_INDEX
-  max_zone = 655;
   if (vzone_num == NOWHERE) {
 #else
-  max_zone = 327;
   if (vzone_num < 0) {
 #endif
     *error = "You can't make negative zones.\r\n";
     return NOWHERE;
    } else if (vzone_num > max_zone) {
 #if CIRCLE_UNSIGNED_INDEX
-    *error = "New zone cannot be higher than 655.\r\n";
+    *error = "New zone cannot be higher than 42949672.\r\n";
 #else
     *error = "New zone cannot be higher than 327.\r\n";
 #endif
@@ -78,7 +76,7 @@
     *error = "Bottom room cannot be less then 0.\r\n";
     return NOWHERE;
   } else if (top >= IDXTYPE_MAX) {
-    *error = "Top greater than IDXTYPE_MAX. (Commonly 65535)\r\n";
+    *error = "Top greater than IDXTYPE_MAX. (42949672).\r\n";
     return NOWHERE;
   }
 
diff -ruN srcbak/objsave.c src/objsave.c
--- srcbak/objsave.c    2020-05-13 08:42:45.690527263 -0400
+++ src/objsave.c       2020-05-13 08:49:45.044581791 -0400
@@ -1026,7 +1026,7 @@
     if (*line == '#') {
       /* check for false alarm. */
       if (sscanf(line, "#%d", &nr) == 1) {
-        /* If we attempt to load an object with a legal VNUM 0-65534, that
+        /* If we attempt to load an object with a legal VNUM 0-42949671, that
          * does not exist, skip it. If the object has a VNUM of NOTHING or
          * 65535, then we assume it doesn't exist on purpose. (Custom Item,
          * Coins, Corpse, etc...) */
diff -ruN srcbak/structs.h src/structs.h
--- srcbak/structs.h    2020-05-13 08:42:45.698527379 -0400
+++ src/structs.h       2020-05-13 08:50:26.429179405 -0400
@@ -28,14 +28,19 @@
  * 0 = use signed indexes; 1 = use unsigned indexes */
 #define CIRCLE_UNSIGNED_INDEX  1
 
+#ifdef UINT_MAX
+#undef UINT_MAX
+#define UINT_MAX 42949672
+#endif
+
 #if CIRCLE_UNSIGNED_INDEX
-# define IDXTYPE       ush_int          /**< Index types are unsigned short ints */
-# define IDXTYPE_MAX USHRT_MAX     /**< Used for compatibility checks. */
-# define IDXTYPE_MIN 0             /**< Used for compatibility checks. */
-# define NOWHERE       ((IDXTYPE)~0)    /**< Sets to ush_int_MAX, or 65,535 */
-# define NOTHING       ((IDXTYPE)~0)    /**< Sets to ush_int_MAX, or 65,535 */
-# define NOBODY                ((IDXTYPE)~0)    /**< Sets to ush_int_MAX, or 65,535 */
-# define NOFLAG   ((IDXTYPE)~0)    /**< Sets to ush_int_MAX, or 65,535 */
+# define IDXTYPE        unsigned int          /**< Index types are unsigned short ints */
+# define IDXTYPE_MAX    UINT_MAX     /**< Used for compatibility checks. */
+# define IDXTYPE_MIN    0             /**< Used for compatibility checks. */
+# define NOWHERE        ((IDXTYPE)~0)    /**< Sets to u_int_MAX, or 42949672 */
+# define NOTHING        ((IDXTYPE)~0)    /**< Sets to u_int_MAX, or 42949672 */
+# define NOBODY         ((IDXTYPE)~0)    /**< Sets to u_int_MAX, or 42949672 */
+# define NOFLAG         ((IDXTYPE)~0)    /**< Sets to u_int_MAX, or 42949672 */
 #else
 # define IDXTYPE       sh_int           /**< Index types are unsigned short ints */
 # define IDXTYPE_MAX SHRT_MAX      /**< Used for compatibility checks. */
@@ -714,7 +719,7 @@
   struct extra_descr_data *ex_description; /**< List of extra descriptions */
   struct char_data *carried_by; /**< Points to PC/NPC carrying, or NULL */
   struct char_data *worn_by; /**< Points to PC/NPC wearing, or NULL */
-  sh_int worn_on; /**< If the object can be worn, where can it be worn? */
+  int  worn_on; /**< If the object can be worn, where can it be worn? */
 
   struct obj_data *in_obj; /**< Points to carrying object, or NULL */
   struct obj_data *contains; /**< List of objects being carried, or NULL */

Please Log in or Create an account to join the conversation.

Time to create page: 0.206 seconds