Changeset - r21576:8f655ba7bab2
[Not reviewed]
master
0 2 0
rubidium - 10 years ago 2014-07-21 18:03:32
rubidium@openttd.org
(svn r26700) -Fix [FS#6066]: incorrect saving of order backups
2 files changed with 11 insertions and 7 deletions:
0 comments (0 inline, 0 general)
src/saveload/order_sl.cpp
Show inline comments
 
@@ -64,255 +64,258 @@ void Order::ConvertFromOldSavegame()
 
		}
 
	} else {
 
		/* Then the depot action flags */
 
		this->SetDepotActionType(((old_flags & 6) == 4) ? ODATFB_HALT : ODATF_SERVICE_ONLY);
 

	
 
		/* Finally fix the depot type flags */
 
		uint t = ((old_flags & 6) == 6) ? ODTFB_SERVICE : ODTF_MANUAL;
 
		if ((old_flags & 2) != 0) t |= ODTFB_PART_OF_ORDERS;
 
		this->SetDepotOrderType((OrderDepotTypeFlags)t);
 
	}
 
}
 

	
 
/**
 
 * Unpacks a order from savegames with version 4 and lower
 
 * @param packed packed order
 
 * @return unpacked order
 
 */
 
static Order UnpackVersion4Order(uint16 packed)
 
{
 
	return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4));
 
}
 

	
 
/**
 
 * Unpacks a order from savegames made with TTD(Patch)
 
 * @param packed packed order
 
 * @return unpacked order
 
 */
 
Order UnpackOldOrder(uint16 packed)
 
{
 
	Order order = UnpackVersion4Order(packed);
 

	
 
	/*
 
	 * Sanity check
 
	 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
 
	 */
 
	if (order.IsType(OT_NOTHING) && packed != 0) order.MakeDummy();
 

	
 
	return order;
 
}
 

	
 
const SaveLoad *GetOrderDescription()
 
{
 
	static const SaveLoad _order_desc[] = {
 
		     SLE_VAR(Order, type,           SLE_UINT8),
 
		     SLE_VAR(Order, flags,          SLE_UINT8),
 
		     SLE_VAR(Order, dest,           SLE_UINT16),
 
		     SLE_REF(Order, next,           REF_ORDER),
 
		 SLE_CONDVAR(Order, refit_cargo,    SLE_UINT8,   36, SL_MAX_VERSION),
 
		SLE_CONDNULL(1,                                  36, 181), // refit_subtype
 
		 SLE_CONDVAR(Order, wait_time,      SLE_UINT16,  67, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Order, travel_time,    SLE_UINT16,  67, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Order, max_speed,      SLE_UINT16, 172, SL_MAX_VERSION),
 

	
 
		/* Leftover from the minor savegame version stuff
 
		 * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
 
		SLE_CONDNULL(10,                                  5,  35),
 
		     SLE_END()
 
	};
 

	
 
	return _order_desc;
 
}
 

	
 
static void Save_ORDR()
 
{
 
	Order *order;
 

	
 
	FOR_ALL_ORDERS(order) {
 
		SlSetArrayIndex(order->index);
 
		SlObject(order, GetOrderDescription());
 
	}
 
}
 

	
 
static void Load_ORDR()
 
{
 
	if (IsSavegameVersionBefore(5, 2)) {
 
		/* Version older than 5.2 did not have a ->next pointer. Convert them
 
		 * (in the old days, the orderlist was 5000 items big) */
 
		size_t len = SlGetFieldLength();
 

	
 
		if (IsSavegameVersionBefore(5)) {
 
			/* Pre-version 5 had another layout for orders
 
			 * (uint16 instead of uint32) */
 
			len /= sizeof(uint16);
 
			uint16 *orders = MallocT<uint16>(len + 1);
 

	
 
			SlArray(orders, len, SLE_UINT16);
 

	
 
			for (size_t i = 0; i < len; ++i) {
 
				Order *o = new (i) Order();
 
				o->AssignOrder(UnpackVersion4Order(orders[i]));
 
			}
 

	
 
			free(orders);
 
		} else if (IsSavegameVersionBefore(5, 2)) {
 
			len /= sizeof(uint32);
 
			uint32 *orders = MallocT<uint32>(len + 1);
 

	
 
			SlArray(orders, len, SLE_UINT32);
 

	
 
			for (size_t i = 0; i < len; ++i) {
 
				new (i) Order(orders[i]);
 
			}
 

	
 
			free(orders);
 
		}
 

	
 
		/* Update all the next pointer */
 
		Order *o;
 
		FOR_ALL_ORDERS(o) {
 
			/* Delete invalid orders */
 
			if (o->IsType(OT_NOTHING)) {
 
				delete o;
 
				continue;
 
			}
 
			/* The orders were built like this:
 
			 * While the order is valid, set the previous will get its next pointer set */
 
			Order *prev = Order::GetIfValid(order_index - 1);
 
			if (prev != NULL) prev->next = o;
 
		}
 
	} else {
 
		int index;
 

	
 
		while ((index = SlIterateArray()) != -1) {
 
			Order *order = new (index) Order();
 
			SlObject(order, GetOrderDescription());
 
			if (IsSavegameVersionBefore(190)) {
 
				order->SetTravelTimetabled(order->GetTravelTime() > 0);
 
				order->SetWaitTimetabled(order->GetWaitTime() > 0);
 
			}
 
		}
 
	}
 
}
 

	
 
static void Ptrs_ORDR()
 
{
 
	/* Orders from old savegames have pointers corrected in Load_ORDR */
 
	if (IsSavegameVersionBefore(5, 2)) return;
 

	
 
	Order *o;
 

	
 
	FOR_ALL_ORDERS(o) {
 
		SlObject(o, GetOrderDescription());
 
	}
 
}
 

	
 
const SaveLoad *GetOrderListDescription()
 
{
 
	static const SaveLoad _orderlist_desc[] = {
 
		SLE_REF(OrderList, first,              REF_ORDER),
 
		SLE_END()
 
	};
 

	
 
	return _orderlist_desc;
 
}
 

	
 
static void Save_ORDL()
 
{
 
	OrderList *list;
 

	
 
	FOR_ALL_ORDER_LISTS(list) {
 
		SlSetArrayIndex(list->index);
 
		SlObject(list, GetOrderListDescription());
 
	}
 
}
 

	
 
static void Load_ORDL()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		/* set num_orders to 0 so it's a valid OrderList */
 
		OrderList *list = new (index) OrderList(0);
 
		SlObject(list, GetOrderListDescription());
 
	}
 

	
 
}
 

	
 
static void Ptrs_ORDL()
 
{
 
	OrderList *list;
 

	
 
	FOR_ALL_ORDER_LISTS(list) {
 
		SlObject(list, GetOrderListDescription());
 
	}
 
}
 

	
 
const SaveLoad *GetOrderBackupDescription()
 
{
 
	static const SaveLoad _order_backup_desc[] = {
 
		     SLE_VAR(OrderBackup, user,                     SLE_UINT32),
 
		     SLE_VAR(OrderBackup, tile,                     SLE_UINT32),
 
		     SLE_VAR(OrderBackup, group,                    SLE_UINT16),
 
		     SLE_VAR(OrderBackup, service_interval,         SLE_UINT32),
 
		 SLE_CONDVAR(OrderBackup, service_interval,         SLE_FILE_U32 | SLE_VAR_U16,  0, 191),
 
		 SLE_CONDVAR(OrderBackup, service_interval,         SLE_UINT16,                192, SL_MAX_VERSION),
 
		     SLE_STR(OrderBackup, name,                     SLE_STR, 0),
 
		     SLE_VAR(OrderBackup, clone,                    SLE_UINT16),
 
		SLE_CONDNULL(2,                                                                  0, 191), // clone (2 bytes of pointer, i.e. garbage)
 
		 SLE_CONDREF(OrderBackup, clone,                    REF_VEHICLE,               192, SL_MAX_VERSION),
 
		     SLE_VAR(OrderBackup, cur_real_order_index,     SLE_UINT8),
 
		 SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_UINT8,                 176, SL_MAX_VERSION),
 
		 SLE_CONDVAR(OrderBackup, current_order_time,       SLE_UINT32,                176, SL_MAX_VERSION),
 
		 SLE_CONDVAR(OrderBackup, lateness_counter,         SLE_INT32,                 176, SL_MAX_VERSION),
 
		 SLE_CONDVAR(OrderBackup, timetable_start,          SLE_INT32,                 176, SL_MAX_VERSION),
 
		 SLE_CONDVAR(OrderBackup, vehicle_flags,            SLE_FILE_U8 | SLE_VAR_U16, 176, 179),
 
		 SLE_CONDVAR(OrderBackup, vehicle_flags,            SLE_UINT16,                180, SL_MAX_VERSION),
 
		     SLE_REF(OrderBackup, orders,                   REF_ORDER),
 
		     SLE_END()
 
	};
 

	
 
	return _order_backup_desc;
 
}
 

	
 
static void Save_BKOR()
 
{
 
	/* We only save this when we're a network server
 
	 * as we want this information on our clients. For
 
	 * normal games this information isn't needed. */
 
	if (!_networking || !_network_server) return;
 

	
 
	OrderBackup *ob;
 
	FOR_ALL_ORDER_BACKUPS(ob) {
 
		SlSetArrayIndex(ob->index);
 
		SlObject(ob, GetOrderBackupDescription());
 
	}
 
}
 

	
 
void Load_BKOR()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		/* set num_orders to 0 so it's a valid OrderList */
 
		OrderBackup *ob = new (index) OrderBackup();
 
		SlObject(ob, GetOrderBackupDescription());
 
	}
 

	
 
	/* Only load order-backups for network clients.
 
	 * If we are a network server or not networking, then we just loaded
 
	 * a previously saved-by-server savegame. There are
 
	 * no clients with a backup anymore, so clear it. */
 
	if (!_networking || _network_server) {
 
	 * If we are a network server or not networking, then we just loaded a previously
 
	 * saved-by-server savegame. There are no clients with a backup, so clear it.
 
	 * Furthermore before savegame version 192 the actual content was always corrupt.
 
	 */
 
	if (!_networking || _network_server || IsSavegameVersionBefore(192)) {
 
		_order_backup_pool.CleanPool();
 
	}
 
}
 

	
 
static void Ptrs_BKOR()
 
{
 
	OrderBackup *ob;
 
	FOR_ALL_ORDER_BACKUPS(ob) {
 
		SlObject(ob, GetOrderBackupDescription());
 
	}
 
}
 

	
 
extern const ChunkHandler _order_chunk_handlers[] = {
 
	{ 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, NULL, CH_ARRAY},
 
	{ 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, NULL, CH_ARRAY},
 
	{ 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, NULL, CH_ARRAY | CH_LAST},
 
};
src/saveload/saveload.cpp
Show inline comments
 
@@ -70,386 +70,387 @@
 
 *    5.1  1440
 
 *    5.2  1525   0.3.6
 
 *    6.0  1721
 
 *    6.1  1768
 
 *    7.0  1770
 
 *    8.0  1786
 
 *    9.0  1909
 
 *   10.0  2030
 
 *   11.0  2033
 
 *   11.1  2041
 
 *   12.1  2046
 
 *   13.1  2080   0.4.0, 0.4.0.1
 
 *   14.0  2441
 
 *   15.0  2499
 
 *   16.0  2817
 
 *   16.1  3155
 
 *   17.0  3212
 
 *   17.1  3218
 
 *   18    3227
 
 *   19    3396
 
 *   20    3403
 
 *   21    3472   0.4.x
 
 *   22    3726
 
 *   23    3915
 
 *   24    4150
 
 *   25    4259
 
 *   26    4466
 
 *   27    4757
 
 *   28    4987
 
 *   29    5070
 
 *   30    5946
 
 *   31    5999
 
 *   32    6001
 
 *   33    6440
 
 *   34    6455
 
 *   35    6602
 
 *   36    6624
 
 *   37    7182
 
 *   38    7195
 
 *   39    7269
 
 *   40    7326
 
 *   41    7348   0.5.x
 
 *   42    7573
 
 *   43    7642
 
 *   44    8144
 
 *   45    8501
 
 *   46    8705
 
 *   47    8735
 
 *   48    8935
 
 *   49    8969
 
 *   50    8973
 
 *   51    8978
 
 *   52    9066
 
 *   53    9316
 
 *   54    9613
 
 *   55    9638
 
 *   56    9667
 
 *   57    9691
 
 *   58    9762
 
 *   59    9779
 
 *   60    9874
 
 *   61    9892
 
 *   62    9905
 
 *   63    9956
 
 *   64   10006
 
 *   65   10210
 
 *   66   10211
 
 *   67   10236
 
 *   68   10266
 
 *   69   10319
 
 *   70   10541
 
 *   71   10567
 
 *   72   10601
 
 *   73   10903
 
 *   74   11030
 
 *   75   11107
 
 *   76   11139
 
 *   77   11172
 
 *   78   11176
 
 *   79   11188
 
 *   80   11228
 
 *   81   11244
 
 *   82   11410
 
 *   83   11589
 
 *   84   11822
 
 *   85   11874
 
 *   86   12042
 
 *   87   12129
 
 *   88   12134
 
 *   89   12160
 
 *   90   12293
 
 *   91   12347
 
 *   92   12381   0.6.x
 
 *   93   12648
 
 *   94   12816
 
 *   95   12924
 
 *   96   13226
 
 *   97   13256
 
 *   98   13375
 
 *   99   13838
 
 *  100   13952
 
 *  101   14233
 
 *  102   14332
 
 *  103   14598
 
 *  104   14735
 
 *  105   14803
 
 *  106   14919
 
 *  107   15027
 
 *  108   15045
 
 *  109   15075
 
 *  110   15148
 
 *  111   15190
 
 *  112   15290
 
 *  113   15340
 
 *  114   15601
 
 *  115   15695
 
 *  116   15893   0.7.x
 
 *  117   16037
 
 *  118   16129
 
 *  119   16242
 
 *  120   16439
 
 *  121   16694
 
 *  122   16855
 
 *  123   16909
 
 *  124   16993
 
 *  125   17113
 
 *  126   17433
 
 *  127   17439
 
 *  128   18281
 
 *  129   18292
 
 *  130   18404
 
 *  131   18481
 
 *  132   18522
 
 *  133   18674
 
 *  134   18703
 
 *  135   18719
 
 *  136   18764
 
 *  137   18912
 
 *  138   18942   1.0.x
 
 *  139   19346
 
 *  140   19382
 
 *  141   19799
 
 *  142   20003
 
 *  143   20048
 
 *  144   20334
 
 *  145   20376
 
 *  146   20446
 
 *  147   20621
 
 *  148   20659
 
 *  149   20832
 
 *  150   20857
 
 *  151   20918
 
 *  152   21171
 
 *  153   21263
 
 *  154   21426
 
 *  155   21453
 
 *  156   21728
 
 *  157   21862
 
 *  158   21933
 
 *  159   21962
 
 *  160   21974   1.1.x
 
 *  161   22567
 
 *  162   22713
 
 *  163   22767
 
 *  164   23290
 
 *  165   23304
 
 *  166   23415
 
 *  167   23504
 
 *  168   23637
 
 *  169   23816
 
 *  170   23826
 
 *  171   23835
 
 *  172   23947
 
 *  173   23967   1.2.0-RC1
 
 *  174   23973   1.2.x
 
 *  175   24136
 
 *  176   24446
 
 *  177   24619
 
 *  178   24789
 
 *  179   24810
 
 *  180   24998   1.3.x
 
 *  181   25012
 
 *  182   25296
 
 *  183   25363
 
 *  184   25508
 
 *  185   25620
 
 *  186   25833
 
 *  187   25899
 
 *  188   26169   1.4.x
 
 *  189   26450
 
 *  190   26547
 
 *  191   26646
 
 *  192   26700
 
 */
 
extern const uint16 SAVEGAME_VERSION = 191; ///< Current savegame version of OpenTTD.
 
extern const uint16 SAVEGAME_VERSION = 192; ///< Current savegame version of OpenTTD.
 

	
 
SavegameType _savegame_type; ///< type of savegame we are loading
 

	
 
uint32 _ttdp_version;     ///< version of TTDP savegame (if applicable)
 
uint16 _sl_version;       ///< the major savegame version identifier
 
byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 
char _savegame_format[8]; ///< how to compress savegames
 
bool _do_autosave;        ///< are we doing an autosave at the moment?
 

	
 
/** What are we currently doing? */
 
enum SaveLoadAction {
 
	SLA_LOAD,        ///< loading
 
	SLA_SAVE,        ///< saving
 
	SLA_PTRS,        ///< fixing pointers
 
	SLA_NULL,        ///< null all pointers (on loading error)
 
	SLA_LOAD_CHECK,  ///< partial loading into #_load_check_data
 
};
 

	
 
enum NeedLength {
 
	NL_NONE = 0,       ///< not working in NeedLength mode
 
	NL_WANTLENGTH = 1, ///< writing length and data
 
	NL_CALCLENGTH = 2, ///< need to calculate the length
 
};
 

	
 
/** Save in chunks of 128 KiB. */
 
static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
 

	
 
/** A buffer for reading (and buffering) savegame data. */
 
struct ReadBuffer {
 
	byte buf[MEMORY_CHUNK_SIZE]; ///< Buffer we're going to read from.
 
	byte *bufp;                  ///< Location we're at reading the buffer.
 
	byte *bufe;                  ///< End of the buffer we can read from.
 
	LoadFilter *reader;          ///< The filter used to actually read.
 
	size_t read;                 ///< The amount of read bytes so far from the filter.
 

	
 
	/**
 
	 * Initialise our variables.
 
	 * @param reader The filter to actually read data.
 
	 */
 
	ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
 
	{
 
	}
 

	
 
	inline byte ReadByte()
 
	{
 
		if (this->bufp == this->bufe) {
 
			size_t len = this->reader->Read(this->buf, lengthof(this->buf));
 
			if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
 

	
 
			this->read += len;
 
			this->bufp = this->buf;
 
			this->bufe = this->buf + len;
 
		}
 

	
 
		return *this->bufp++;
 
	}
 

	
 
	/**
 
	 * Get the size of the memory dump made so far.
 
	 * @return The size.
 
	 */
 
	size_t GetSize() const
 
	{
 
		return this->read - (this->bufe - this->bufp);
 
	}
 
};
 

	
 

	
 
/** Container for dumping the savegame (quickly) to memory. */
 
struct MemoryDumper {
 
	AutoFreeSmallVector<byte *, 16> blocks; ///< Buffer with blocks of allocated memory.
 
	byte *buf;                              ///< Buffer we're going to write to.
 
	byte *bufe;                             ///< End of the buffer we write to.
 

	
 
	/** Initialise our variables. */
 
	MemoryDumper() : buf(NULL), bufe(NULL)
 
	{
 
	}
 

	
 
	/**
 
	 * Write a single byte into the dumper.
 
	 * @param b The byte to write.
 
	 */
 
	inline void WriteByte(byte b)
 
	{
 
		/* Are we at the end of this chunk? */
 
		if (this->buf == this->bufe) {
 
			this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
 
			*this->blocks.Append() = this->buf;
 
			this->bufe = this->buf + MEMORY_CHUNK_SIZE;
 
		}
 

	
 
		*this->buf++ = b;
 
	}
 

	
 
	/**
 
	 * Flush this dumper into a writer.
 
	 * @param writer The filter we want to use.
 
	 */
 
	void Flush(SaveFilter *writer)
 
	{
 
		uint i = 0;
 
		size_t t = this->GetSize();
 

	
 
		while (t > 0) {
 
			size_t to_write = min(MEMORY_CHUNK_SIZE, t);
 

	
 
			writer->Write(this->blocks[i++], to_write);
 
			t -= to_write;
 
		}
 

	
 
		writer->Finish();
 
	}
 

	
 
	/**
 
	 * Get the size of the memory dump made so far.
 
	 * @return The size.
 
	 */
 
	size_t GetSize() const
 
	{
 
		return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
 
	}
 
};
 

	
 
/** The saveload struct, containing reader-writer functions, buffer, version, etc. */
 
struct SaveLoadParams {
 
	SaveLoadAction action;               ///< are we doing a save or a load atm.
 
	NeedLength need_length;              ///< working in NeedLength (Autolength) mode?
 
	byte block_mode;                     ///< ???
 
	bool error;                          ///< did an error occur or not
 

	
 
	size_t obj_len;                      ///< the length of the current object we are busy with
 
	int array_index, last_array_index;   ///< in the case of an array, the current and last positions
 

	
 
	MemoryDumper *dumper;                ///< Memory dumper to write the savegame to.
 
	SaveFilter *sf;                      ///< Filter to write the savegame to.
 

	
 
	ReadBuffer *reader;                  ///< Savegame reading buffer.
 
	LoadFilter *lf;                      ///< Filter to read the savegame from.
 

	
 
	StringID error_str;                  ///< the translatable error message to show
 
	char *extra_msg;                     ///< the error message
 

	
 
	byte ff_state;                       ///< The state of fast-forward when saving started.
 
	bool saveinprogress;                 ///< Whether there is currently a save in progress.
 
};
 

	
 
static SaveLoadParams _sl; ///< Parameters used for/at saveload.
 

	
 
/* these define the chunks */
 
extern const ChunkHandler _gamelog_chunk_handlers[];
 
extern const ChunkHandler _map_chunk_handlers[];
 
extern const ChunkHandler _misc_chunk_handlers[];
 
extern const ChunkHandler _name_chunk_handlers[];
 
extern const ChunkHandler _cheat_chunk_handlers[] ;
 
extern const ChunkHandler _setting_chunk_handlers[];
 
extern const ChunkHandler _company_chunk_handlers[];
 
extern const ChunkHandler _engine_chunk_handlers[];
 
extern const ChunkHandler _veh_chunk_handlers[];
 
extern const ChunkHandler _waypoint_chunk_handlers[];
 
extern const ChunkHandler _depot_chunk_handlers[];
 
extern const ChunkHandler _order_chunk_handlers[];
 
extern const ChunkHandler _town_chunk_handlers[];
 
extern const ChunkHandler _sign_chunk_handlers[];
 
extern const ChunkHandler _station_chunk_handlers[];
 
extern const ChunkHandler _industry_chunk_handlers[];
 
extern const ChunkHandler _economy_chunk_handlers[];
 
extern const ChunkHandler _subsidy_chunk_handlers[];
 
extern const ChunkHandler _cargomonitor_chunk_handlers[];
 
extern const ChunkHandler _goal_chunk_handlers[];
 
extern const ChunkHandler _story_page_chunk_handlers[];
 
extern const ChunkHandler _ai_chunk_handlers[];
 
extern const ChunkHandler _game_chunk_handlers[];
 
extern const ChunkHandler _animated_tile_chunk_handlers[];
 
extern const ChunkHandler _newgrf_chunk_handlers[];
 
extern const ChunkHandler _group_chunk_handlers[];
 
extern const ChunkHandler _cargopacket_chunk_handlers[];
 
extern const ChunkHandler _autoreplace_chunk_handlers[];
 
extern const ChunkHandler _labelmaps_chunk_handlers[];
 
extern const ChunkHandler _linkgraph_chunk_handlers[];
 
extern const ChunkHandler _airport_chunk_handlers[];
 
extern const ChunkHandler _object_chunk_handlers[];
 
extern const ChunkHandler _persistent_storage_chunk_handlers[];
 

	
 
/** Array of all chunks in a savegame, \c NULL terminated. */
 
static const ChunkHandler * const _chunk_handlers[] = {
 
	_gamelog_chunk_handlers,
 
	_map_chunk_handlers,
 
	_misc_chunk_handlers,
 
	_name_chunk_handlers,
 
	_cheat_chunk_handlers,
 
	_setting_chunk_handlers,
0 comments (0 inline, 0 general)