保存変数について

返信する
ppp
記事: 48
登録日時: 2022年9月28日(水) 21:50

保存変数について

投稿記事 by ppp »

質問失礼します。現在プラグインを制作中なのですが、保存変数が保存されないという問題が発生しております。
$gamePartyにthis._uniqueItemが保存されません。他のプラグインで$gamePartyに同じような処理を書いたものは問題なく動作します。ご回答お待ちしております。
試したのは
・他のプラグインとの兼ね合い←他のプラグインを全部抜いても保存されない。
・変数の定義を即時関数の外側においてみる←だめでした。
長くなりますが、以下コードです。

コード: 全て選択

/*:
 * @plugindesc ユニークアイテムIDプラグイン
 * @author PPP
 * @help MV ユニークアイテムIDを設定するプラグインです。
 *
 */

(function () {
    "use strict";
    const pluginName = 'PPP_UniqueItemId';

    var UniqueItemId = UniqueItemId || {};
	
    UniqueItemId.ITEM_ORIGIN_ID   = 2001;
	UniqueItemId.WEAPON_ORIGIN_ID = 2001;
	UniqueItemId.ARMOR_ORIGIN_ID  = 2001;
	
	UniqueItemId.linkUniqueItem = function(dataArray, uniqueItem) {
        if (uniqueItem && dataArray[uniqueItem.originalId]) {
	        dataArray[uniqueItem.id] = Object.assign({}, dataArray[uniqueItem.originalId]);
		    dataArray[uniqueItem.id].id = uniqueItem.id;
		}
	};
	
	UniqueItemId.unlinkUniqueItem = function(dataArray, uniqueItem) {
		if (uniqueItem && dataArray[uniqueItem.id]) {
		    delete dataArray[uniqueItem.id];
			while (dataArray.length > 0 && !dataArray[dataArray.length - 1]) {
                dataArray.pop();
            }
		}
	};

    UniqueItemId.minIndex = function(array, originId) {
		array = array.slice(originId);
        var id = array.findIndex(element => !element);
        return id !== -1 ? id + originId : array.length + originId;
    };
	
	// Game_Party
	
    var _Game_Party_initialize = Game_Party.prototype.initialize;
    Game_Party.prototype.initialize = function() {
        _Game_Party_initialize.apply(this, arguments);
		console.log(this._uniqueItems);
		this._uniqueItems = this._uniqueItems || {};
		this._uniqueItems.items   = this._uniqueItems.items   || [];
		this._uniqueItems.weapons = this._uniqueItems.weapons || [];
		this._uniqueItems.armors  = this._uniqueItems.armors  || [];
        this._lastUniqueItem = this._lastUniqueItem || null;
        this.restoreUniqueItem();
    };
	
    Game_Party.prototype.restoreUniqueItem = function() {
        this._uniqueItems.items.forEach(item => 
	    	UniqueItemId.linkUniqueItem($dataItems, item));

        this._uniqueItems.weapons.forEach(weapon => 
	    	UniqueItemId.linkUniqueItem($dataWeapons, weapon));
	
        this._uniqueItems.armors.forEach(armor => 
		    UniqueItemId.linkUniqueItem($dataArmors, armor));
    };
    
    Game_Party.prototype.gainUniqueItem = function(item) {
        if (DataManager.isItem(item)) {
			var uniqueItem = this.createUniqueItem(this.getOriginalItemId(item));

			UniqueItemId.linkUniqueItem($dataItems, uniqueItem);
            this.gainItem($dataItems[uniqueItem.id], 1);

            this._lastUniqueItem = $dataItems[uniqueItem.id];
		
        } else if (DataManager.isWeapon(item)) {
			var uniqueWeapon = this.createUniqueWeapon(this.getOriginalItemId(item));

			UniqueItemId.linkUniqueItem($dataWeapons, uniqueWeapon);
            this.gainItem($dataWeapons[uniqueWeapon.id], 1);
			
			this._lastUniqueItem = $dataWeapons[uniqueWeapon.id];
			
        } else if (DataManager.isArmor(item)) {
			var uniqueArmor = this.createUniqueArmor(this.getOriginalItemId(item));

			UniqueItemId.linkUniqueItem($dataArmors, uniqueArmor);
            this.gainItem($dataArmors[uniqueArmor.id], 1);
			
			this._lastUniqueItem = $dataArmors[uniqueArmor.id];
        }
	};
	
	var _Game_Party_loseItem = Game_Party.prototype.loseItem;
	Game_Party.prototype.loseItem = function(item, amount, includeEquip) {
		if (DataManager.isItem(item)) {
			var uniqueItem = this._uniqueItems.items[item.id];

			UniqueItemId.unlinkUniqueItem($dataItems, uniqueItem);

        } else if (DataManager.isWeapon(item)) {
			var uniqueWeapon = this._uniqueItems.weapons[item.id];

			UniqueItemId.unlinkUniqueItem($dataWeapons, uniqueWeapon);

        } else if (DataManager.isArmor(item)) {
			var uniqueArmor = this._uniqueItems.armors[item.id];

			UniqueItemId.unlinkUniqueItem($dataArmors, uniqueArmor);

        }
		_Game_Party_loseItem.call(this, item, amount, includeEquip);
	};
	
	Game_Party.prototype.getLastUniqueItem = function() {
		return this._lastUniqueItem;
	};
	
	Game_Party.prototype.getOriginalItemId = function(item) {
		if (DataManager.isItem(item)) {
			var uniqueItem = this._uniqueItems.items[item.id];
            return uniqueItem ? uniqueItem.originalId : item.id;

        } else if (DataManager.isWeapon(item)) {
			var uniqueWeapon = this._uniqueItems.weapons[item.id];
            return uniqueWeapon ? uniqueWeapon.originalId : item.id;

        } else if (DataManager.isArmor(item)) {
			var uniqueArmor = this._uniqueItems.armors[item.id];
            return uniqueArmor ? uniqueArmor.originalId : item.id;

        }
	};
	
	Game_Party.prototype.createUniqueItem = function(originalId) {
		var id = UniqueItemId.minIndex(this._uniqueItems.items, UniqueItemId.ITEM_ORIGIN_ID);

		this._uniqueItems.items[id] = {
			id: id,
			originalId: originalId,
			variables: {}
		};
	    return this._uniqueItems.items[id];
	};
	
	Game_Party.prototype.createUniqueWeapon = function(originalId) {
		var id = UniqueItemId.minIndex(this._uniqueItems.weapons, UniqueItemId.WEAPON_ORIGIN_ID);
		console.log(id)
    	this._uniqueItems.weapons[id] = {
			id: id, 
			originalId: originalId,
			variables: {}
		};
	    return this._uniqueItems.weapons[id];
	};
	
	Game_Party.prototype.createUniqueArmor = function(originalId, id) {
		var id = UniqueItemId.minIndex(this._uniqueItems.armors, UniqueItemId.ARMOR_ORIGIN_ID);
		
	    this._uniqueItems.armors[id] = {
			id: id, 
			originalId: originalId,
			variables: {}
		};
	    return this._uniqueItems.armors[id];
	};
	
    Game_Party.prototype.getItemVariable = function(item, index) {
		var uniqueItem = null;
		
        if (DataManager.isItem(item)) {
            uniqueItem = this._uniqueItems.items[item.id];
        } else if (DataManager.isWeapon(item)) {
            uniqueItem = this._uniqueItems.weapons[item.id];
        } else if (DataManager.isArmor(item)) {
            uniqueItem = this._uniqueItems.armors[item.id];
        }

		if (uniqueItem) {
			return uniqueItem.variables ? uniqueItem.variables[index] : undefined;
		}
        return undefined;
    };
    
    Game_Party.prototype.setItemVariable = function(item, index, value) {
		var uniqueItem = null;
		
        if (DataManager.isItem(item)) {
            uniqueItem = this._uniqueItems.items[item.id];
        } else if (DataManager.isWeapon(item)) {
            uniqueItem = this._uniqueItems.weapons[item.id];
        } else if (DataManager.isArmor(item)) {
            uniqueItem = this._uniqueItems.armors[item.id];
        }

		if (uniqueItem) {
            uniqueItem.variables = uniqueItem.variables || {};
			uniqueItem.variables[index] = value;
		}
    };
    
	Game_Party.prototype.uniqueItems = function() {
	    return this._uniqueItems.items;	
	};

	Game_Party.prototype.uniqueWeapons = function() {
	    return this._uniqueItems.weapons;	
	};
	
	Game_Party.prototype.uniqueArmors = function() {
	    return this._uniqueItems.armors;	
	};
	
	var _Game_Party_items = Game_Party.prototype.items;
	Game_Party.prototype.items = function() {
		var items = _Game_Party_items.apply(this);
		return items.filter(item => item);
	};
	
	var _Game_Party_weapons = Game_Party.prototype.weapons;
	Game_Party.prototype.weapons = function() {
		var weapons = _Game_Party_weapons.apply(this);
		return weapons.filter(weapon => weapon);
	};
	
	var _Game_Party_armors = Game_Party.prototype.armors;
	Game_Party.prototype.armors = function() {
		var armors = _Game_Party_armors.apply(this);
		return armors.filter(armor => armor);
	};
    
	var _DataManager_isItem = DataManager.isItem;
	DataManager.isItem = function(item) {
		return item && !!$gameParty.uniqueItems()[item.id] || _DataManager_isItem.call(this, item);
	};
	
	var _DataManager_isWeapon = DataManager.isWeapon;
	DataManager.isWeapon = function(item) {
		return item && !!$gameParty.uniqueWeapons()[item.id] || _DataManager_isWeapon.call(this, item);
	};
	
	var _DataManager_isArmor = DataManager.isArmor;
	DataManager.isArmor = function(item) {
		return item && !!$gameParty.uniqueArmors()[item.id] || _DataManager_isArmor.call(this, item);
	};
    
})();
最後に編集したユーザー ppp [ 2024年9月23日(月) 22:00 ], 累計 1 回
アバター
Plasma Dark
記事: 736
登録日時: 2020年2月08日(土) 02:29
連絡する:

Re: 保存変数について

投稿記事 by Plasma Dark »

保存されないとはどういうことですか?
あなたが考えているシステムについて何も知らない人が、即座に状況を再現できるような情報を提供してください。

ご提示頂いたコードをプラグイン PPP_UniqueItemId.js として読み込み、下記スクリプトを実行してセーブ&ロードすると、 _uniqueItems は正しく保存されているようでした。

コード: 全て選択

$gameParty.gainUniqueItem($dataItems[1]);

以下余談です。

インデントが独特

意図したものでなければ、エディタのフォーマット機能を活用するとキレイにできます。
VSCode (Windows) であれば Shift + Alt + F ですね。

UniqueItemの配列のindex採番

2001から割り当てているようなので、これだと0~2000の範囲には最終的にnullが入ります。
(セーブ&ロードするまではundefinedですが、ロードするとnullになります)
元のデータと重複しないIDがほしいのであれば、 uniqueId みたいな要素を足してあげて、配列の添字はそれとは関係ない値にするとか、ランダムアクセスを考慮したいなら配列ではなくオブジェクトやMap型にする手もありそうです。

データを丸ごと保存すべきか

見る限りだと、データベースに登録された情報を丸ごとコピーし、それにnumber型のオリジナルIDとvariablesなるオブジェクトを追加しているようですね。
全部保存しないといけないのかは、考えても良さそうです。
入手したアイテムそれぞれに付加情報を持たせる意図のプラグインであるとすると、それらすべてについて元データをコピーした場合、最終的に無駄になるデータが多くなりすぎるおそれがあります。

例えば、こんな形のクラスを作ってしまえば、IDとvariables(と、クラス情報)だけ保存しておいて、元になったアイテムのデータはセーブデータに含めなくても良くなります。

コード: 全て選択

class Game_UniqueItem {
  _originalId: number;
  _uniqueId: number;
  _variables: {[key: number]: number};

  constructor(originalId, uniqueId) {
    this._originalId = originalId;
    this._uniqueId = uniqueId;
    this._variables = {};
  }

  data(): RPG.Item {
    return $dataItems[this._originalId];
  };
}
※TypeScriptで書いているので、適宜読み替えてください。
※クラスにする場合はクラス名をグローバルに公開しておかないと正しくセーブデータに追加できません。
ppp
記事: 48
登録日時: 2022年9月28日(水) 21:50

Re: 保存変数について

投稿記事 by ppp »

回答ありがとうございます。自分の環境だと保存されないみたいなので、環境に問題があるようです。他のプラグインでは保存されるようなので、その違いを探ってみるしかなさそうです。
ecf5DTTzl6h6lJj02
記事: 752
登録日時: 2018年12月23日(日) 13:55

Re: 保存変数について

投稿記事 by ecf5DTTzl6h6lJj02 »

こんにちは。
ちょっと横から失礼します。
ppp さんが書きました:回答ありがとうございます。自分の環境だと保存されないみたいなので、環境に問題があるようです。他のプラグインでは保存されるようなので、その違いを探ってみるしかなさそうです。
もしかして、提示されているコードの
Game_Party.prototype.initialize の中に記述している、

コード: 全て選択

console.log(this._uniqueItems);
の出力結果を見て、データが保存されていないって言っていますか?
このタイミングだと、
セーブデータが展開される前ですし、
データが何も入っていない状態で出力していますので、
undefined が出力されるはずです。
データをロードした後に、
コンソールから上記コードで確認すれば、
きちんと、データが保存されていることが確認できるのではないでしょうか。

これとは別に気になるのが、
restoreUniqueItem というメソッド。
ユニークアイテムのIDの紐づけをし直すメソッドみたいですが、
これって、セーブデータをロードした後に呼び出されなくて、良いのでしょうか?
上記と同じく、
Game_Party.prototype.initialize の中で呼ばれているので、
セーブデータが展開される前に、実行されていて、
セーブデータの内容に対しては実行されていないはずです。

セーブデータをロードする際の処理の流れを、
きちんと確認してみてください。
ppp
記事: 48
登録日時: 2022年9月28日(水) 21:50

Re: 保存変数について

投稿記事 by ppp »

回答有り難うございます。おっしゃるとおり、「initializeの時点でセーブデータが復元されている」という勘違いでした。お騒がせ失礼しました。extractSaveContentsの段階で復元することでうまくいきました!
返信する

“MV:質問”に戻る