Review the merged code to resolve an issue where the game is unresponsive after a player dies.

审查合并后的代码,解决玩家死亡后游戏无响应的问题。
This commit is contained in:
Cold-Mint 2024-06-13 22:29:18 +08:00
parent c957faec76
commit b8b8e81d8f
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
20 changed files with 109 additions and 67 deletions

View File

@ -29,7 +29,7 @@ public class PatrolBehaviorTree : BehaviorTreeTemplate
return patrolNode;
}
protected override string? CreateId()
protected override string CreateId()
{
return Config.BehaviorTreeId.Patrol;
}

View File

@ -4,8 +4,6 @@ using System.Threading.Tasks;
using ColdMint.scripts.damage;
using ColdMint.scripts.deathInfo;
using ColdMint.scripts.debug;
using ColdMint.scripts.inventory;
using ColdMint.scripts.item;
using ColdMint.scripts.map.events;
using ColdMint.scripts.utils;

View File

@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ColdMint.scripts.item;

View File

@ -63,7 +63,7 @@ public partial class ItemSlotNode : MarginContainer
if (_itemStack is null) return null;
var result = _itemStack.PickItem();
if (_itemStack.Quantity == 0) _itemStack = null;
if (_itemStack.Empty) _itemStack = null;
UpdateAllDisplay();
return result;
@ -83,7 +83,7 @@ public partial class ItemSlotNode : MarginContainer
if (_itemStack is null) return null;
var result = _itemStack.PickItems(value);
if (_itemStack.Quantity == 0) _itemStack = null;
if (_itemStack.Empty) _itemStack = null;
UpdateAllDisplay();
return result;
@ -115,7 +115,7 @@ public partial class ItemSlotNode : MarginContainer
var result = _itemStack.RemoveItem(number);
//If the specified number of items is removed, the number of items is less than or equal to 0. Then we empty the inventory.
//如果移除指定数量的物品后物品数量小于或等于0。那么我们清空物品栏。
if (_itemStack.Quantity == 0) _itemStack = null;
if (_itemStack.Empty) _itemStack = null;
UpdateAllDisplay();
return result;

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using ColdMint.scripts.debug;
using Godot;

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;
using ColdMint.scripts.debug;
using ColdMint.scripts.utils;
using Godot;

View File

@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.Linq;
using ColdMint.scripts.character;
using ColdMint.scripts.debug;
using ColdMint.scripts.item;
using ColdMint.scripts.item.itemStacks;
using ColdMint.scripts.utils;

View File

@ -3,13 +3,9 @@
namespace ColdMint.scripts.item;
/// <summary>
/// <para>Special item interface that make item common, which means will stack in a <see cref="CommonItemStack"/></para>
/// <para>该特殊的物品接口使得物品成为平凡物品,换言之,将会堆叠在<see cref="CommonItemStack"/></para>中。
/// <para>The special item interface makes the item a normal item, in other words, will be stacked in<see cref="CommonItemStack"/></para>
/// <para>该特殊的物品接口使得物品成为普通的物品,换言之,将会堆叠在<see cref="CommonItemStack"/>中。</para>
/// </summary>
/// <typeparam name="TSelf">
/// <para>Make this the class itself</para>
/// <para>应当为当前类自身</para>
/// </typeparam>
/// <remarks>
/// <para>
/// Notice when you implement: To avoid unexpected behavior, unless you understand what you're doing, the <see cref="IItem.CanStackWith"/> method

View File

@ -8,23 +8,28 @@ public interface IItem
{
/// <summary>
/// <para>ID of current item</para>
/// <para>当前项目的ID</para>
/// </summary>
string Id { get; }
/// <summary>
/// <para>Icon of current item</para>
/// <para>当前项目的图标</para>
/// </summary>
Texture2D Icon { get; }
/// <summary>
/// <para>Display name of current item</para>
/// <para>显示当前Item的名称</para>
/// </summary>
string Name { get; }
/// <summary>
/// <para>Description of current item, which may show in inventory</para>
/// <para>当前项目的描述</para>
/// </summary>
string? Description { get; }
/// <summary>
/// <para>Execute when current item is used <br/> e.g. when player clicks left mouse button with current item in hand</para>
/// <para>当前项被使用时执行 <br/> e.g. 当玩家用鼠标左键点击当前物品时</para>
/// </summary>
/// <param name="owner">Owner of current item, if any</param>
/// <param name="targetGlobalPosition">Target position, such as the position of the cursor when used by the player</param>
@ -32,6 +37,7 @@ public interface IItem
/// <summary>
/// <para>Execute when current item be removed from game.</para>
/// <para>当前物品从游戏中移除时执行。</para>
/// </summary>
void Destroy();
@ -67,7 +73,7 @@ public interface IItem
/// </summary>
/// <remarks>
/// <para>DO NOT use this method to create stack from item, use <see cref="IItemStack.FromItem"/> instead</para>
/// <para>**不要**使用此方法从一个物品创建堆,请使用 <see cref="IItemStack.FromItem"/></para>。
/// <para>不要使用此方法从一个物品创建堆,请使用 <see cref="IItemStack.FromItem"/></para>。
/// </remarks>
/// <seealso cref="CanStackWith"/>
IItemStack? SpecialStack() => null;

View File

@ -4,7 +4,7 @@ using Godot;
namespace ColdMint.scripts.item;
public readonly struct ItemType(string id, Func<IItem> newItemFunc, Texture2D? icon, int maxStackQuantity)
public readonly struct ItemType(string id, Func<IItem?> newItemFunc, Texture2D? icon, int maxStackQuantity)
{
/// <summary>
/// <para>Item id of this type</para>
@ -15,7 +15,7 @@ public readonly struct ItemType(string id, Func<IItem> newItemFunc, Texture2D? i
/// <para>A function returns a new item instance of this type</para>
/// <para>用于创建该类型的物品实例的函数</para>
/// </summary>
public Func<IItem> NewItemFunc { get; init; } = newItemFunc;
public Func<IItem?> NewItemFunc { get; init; } = newItemFunc;
/// <summary>
/// <para>Default icon of items of this type</para>
/// <para>该类型物品的默认图标</para>

View File

@ -1,27 +1,34 @@
using System.Collections.Generic;
using ColdMint.scripts.item.weapon;
using ColdMint.scripts.utils;
using Godot;
namespace ColdMint.scripts.item;
/// <summary>
/// <para>Item manager</para>
/// <para>物品管理器</para>
/// </summary>
public static class ItemTypeManager
{
/// <summary>
/// Register items statically here
/// <para>Register items here</para>
/// <para>在这里注册物品</para>
/// </summary>
public static void StaticRegister()
{
var staffOfTheUndeadScene = ResourceLoader.Load<PackedScene>("res://prefab/weapons/staffOfTheUndead.tscn");
var staffOfTheUndeadIcon = ResourceLoader.Load<Texture2D>("res://sprites/weapon/staffOfTheUndead.png");
var staffOfTheUndead =
new ItemType("staff_of_the_undead", () => staffOfTheUndeadScene.Instantiate<IItem>(), staffOfTheUndeadIcon, 1);
new ItemType("staff_of_the_undead",
() => NodeUtils.InstantiatePackedScene<ProjectileWeapon>(staffOfTheUndeadScene), staffOfTheUndeadIcon,
1);
Register(staffOfTheUndead);
var packsackScene = ResourceLoader.Load<PackedScene>("res://prefab/packsacks/packsack.tscn");
var packsackIcon = ResourceLoader.Load<Texture2D>("res://sprites/Player.png");
var packsack = new ItemType("packsack", () => packsackScene.Instantiate<IItem>(), packsackIcon, 1);
var packsack = new ItemType("packsack", () => NodeUtils.InstantiatePackedScene<Packsack>(packsackScene),
packsackIcon, 1);
Register(packsack);
}
@ -30,10 +37,14 @@ public static class ItemTypeManager
/// <summary>
/// Register an item type.
/// Return false if the item id already exist.
/// <para>Register an item type.</para>
/// <para>Return false if the item id already exist.</para>
/// <para>注册一个物品类型</para>
/// <para>如果项目id已经存在则返回false。</para>
/// </summary>
/// <returns>Whether the registration was successful.</returns>
/// <returns><para>Whether the registration was successful.</para>
/// <para>注册是否成功。</para>
/// </returns>
public static bool Register(ItemType itemType) => Registry.TryAdd(itemType.Id, itemType);
/// <summary>
@ -70,5 +81,15 @@ public static class ItemTypeManager
? itemType.Icon ?? DefaultTexture
: DefaultTexture;
public static int MaxStackQuantityOf(string id) => Registry.TryGetValue(id, out var itemType) ? itemType.MaxStackQuantity : 0;
/// <summary>
/// <para>Gets the maximum number of stacks for an item</para>
/// <para>获取某个物品的最大堆叠数量</para>
/// </summary>
/// <param name="id">
///<para>id</para>
///<para>物品ID</para>
/// </param>
/// <returns></returns>
public static int MaxStackQuantityOf(string id) =>
Registry.TryGetValue(id, out var itemType) ? itemType.MaxStackQuantity : 0;
}

View File

@ -1,18 +1,22 @@
using System;
using Godot;
namespace ColdMint.scripts.item.itemStacks;
/// <summary>
/// <para>
/// one of the basic item stacks, where there is only one instance of an item actually held in the stack,
/// meaning that all items are identical (or completely random in some ways)
/// </para>
/// <para>平凡物品堆,基础物品堆之一,堆中实际保存的物品实例仅有一个,意味着所有物品都完全一致(或某些方面完全随机)</para>
/// <para>An ordinary item pile, in which only one instance of the item is actually saved.</para>
/// <para>普通的物品堆,堆中实际保存的物品实例仅有一个。</para>
/// </summary>
/// <param name="innerItem"></param>
/// <seealso cref="UniqueItemStack"/><seealso cref="SingleItemStack"/>
/// <remarks>
///<para>When the <see cref="AddItem"/> method is called in this implementation, the number of internal items is increased by one and new items passed in are destroyed.</para>
///<para>在此实现下调用<see cref="AddItem"/>方法时,会对内部物品的数量加一,并销毁传递进来的新物品。</para>
/// </remarks>
/// <param name="innerItem">
///<para>innerItem</para>
///<para>内部物品</para>
/// </param>
/// <seealso cref="UniqueItemStack"/>
/// <seealso cref="SingleItemStack"/>
public class CommonItemStack(ICommonItem innerItem) : IItemStack
{
public int MaxQuantity { get; } = ItemTypeManager.MaxStackQuantityOf(innerItem.Id);
@ -31,12 +35,18 @@ public class CommonItemStack(ICommonItem innerItem) : IItemStack
{
if (!CanAddItem(item)) return false;
Quantity++;
item.Destroy();
return true;
}
public int CanTakeFrom(IItemStack itemStack)
{
if (itemStack.Empty || !innerItem.CanStackWith(itemStack.GetItem()!)) return 0;
var item = itemStack.GetItem();
if (item == null)
{
return 0;
}
if (itemStack.Empty || !innerItem.CanStackWith(item)) return 0;
return Math.Min(itemStack.Quantity, MaxQuantity - Quantity);
}
@ -55,10 +65,11 @@ public class CommonItemStack(ICommonItem innerItem) : IItemStack
public IItem? PickItem()
{
if (Empty) return null;
if(Empty) return null;
Quantity--;
if (Empty) innerItem.Destroy();
return innerItem.CopyInstance();
var result = innerItem.CopyInstance();
if(Empty) innerItem.Destroy();
return result;
}
public IItemStack? PickItems(int value)
@ -66,6 +77,10 @@ public class CommonItemStack(ICommonItem innerItem) : IItemStack
if (Empty) return null;
var result = new CommonItemStack(innerItem.CopyInstance());
var n = Math.Min(Quantity, value);
if (n < 0)
{
n = Quantity;
}
result.Quantity = n;
Quantity -= n;
if (Empty) innerItem.Destroy();
@ -75,6 +90,10 @@ public class CommonItemStack(ICommonItem innerItem) : IItemStack
public int RemoveItem(int number)
{
var n = Math.Min(number, Quantity);
if (n < 0)
{
n = Quantity;
}
Quantity -= n;
if (Empty) innerItem.Destroy();
return number - n;

View File

@ -1,10 +1,10 @@
using System;
using Godot;
namespace ColdMint.scripts.item.itemStacks;
/// <summary>
/// <para>物品槽中的物品堆</para>
/// <para>Item stack in an inventory slot</para>
/// </summary>
public interface IItemStack
@ -60,13 +60,21 @@ public interface IItemStack
public bool CanAddItem(IItem item);
/// <summary>
/// <para>Hold a given item</para>
/// <para>Add items to the itemStack</para>
/// <para>添加物品到物品堆内</para>
/// </summary>
/// <param name="item">Item to hold by current stack</param>
/// <returns>Whether successful</returns>
/// <param name="item">
///<para>Items to add</para>
///<para>需要添加的物品</para>
/// </param>
/// <returns>
///<para>Whether successful</para>
///<para>是否成功</para>
/// </returns>
public bool AddItem(IItem item);
/// <summary>
/// <para>Determines the number of items that can be received from the specified pile</para>
/// <para>判断能从指定物品堆中接收的物品数量</para>
/// </summary>
/// <param name="itemStack">
@ -77,19 +85,22 @@ public interface IItemStack
public int CanTakeFrom(IItemStack itemStack);
/// <summary>
/// <para>Move as many items as possible from the specified item pile to the current item pile. Items that have been moved to the current item pile should be removed from the original item pile.</para>
/// <para>将指定物品堆中尽可能多的物品移动至当前物品堆中,被移入当前堆的物品应从原物品堆中移除。</para>
/// </summary>
/// <param name="itemStack">
/// <para>The pile of items that are moved into the current pile</para>
/// <para>被移入当前堆的物品堆</para>
/// </param>
/// <returns>
/// <para>Whether the original stack is empty after the operation</para>
/// <para>操作结束后原物品堆是否为空</para>
/// </returns>
public bool TakeFrom(IItemStack itemStack);
/// <summary>
/// <para>Get item instance at the top of current stack without removing it from stack</para>
/// <para>获取当前物品堆顶部的物品实例而不取出该物品</para>
/// <para>Gets an item instance of the current item pile without retrieving the item</para>
/// <para>获取当前物品堆的物品实例而不取出该物品</para>
/// <seealso cref="PickItem"/>
/// </summary>
/// <returns></returns>
@ -152,8 +163,9 @@ public interface IItemStack
item.SpecialStack() ??
ItemTypeManager.MaxStackQuantityOf(item.Id) switch
{
1 => new SingleItemStack(item),
> 1 => item is ICommonItem commonItem ? new CommonItemStack(commonItem) : new UniqueItemStack(item),
var other => throw new ArgumentException($"item {item} of type '{item.Id}' has unexpected max stack quantity {other}")
1 => new SingleItemStack(item),
> 1 => item is ICommonItem commonItem ? new CommonItemStack(commonItem) : new UniqueItemStack(item),
var other => throw new ArgumentException(
$"item {item} of type '{item.Id}' has unexpected max stack quantity {other}")
};
}

View File

@ -5,17 +5,18 @@ using Godot;
namespace ColdMint.scripts.item.itemStacks;
/// <summary>
/// <para>One of the basic item stacks, there are always one item in stack</para>
/// <para>单身狗物品堆,基础物品堆之一,堆中永远只会有一个物品</para>
/// <para>One of the basic item stacks, there are always one item in stack(Stack not supported)</para>
/// <para>单身狗物品堆,基础物品堆之一,堆中永远只会有一个物品(不支持堆叠)</para>
/// </summary>
/// <seealso cref="UniqueItemStack"/><seealso cref="CommonItemStack"/>
/// <seealso cref="UniqueItemStack"/>
/// <seealso cref="CommonItemStack"/>
public class SingleItemStack(IItem item) : IItemStack
{
public IItem Item { get; init; } = item;
public int MaxQuantity => 1;
public int Quantity => 1;
public bool Empty { get; private set; } = false;
public bool Empty { get; private set; }
public Texture2D Icon => Item.Icon;
public string Name => Item.Name;
public string? Description => Item.Description;

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Godot;
namespace ColdMint.scripts.item.itemStacks;
@ -22,6 +20,7 @@ public class UniqueItemStack : IItemStack
MaxQuantity = ItemTypeManager.MaxStackQuantityOf(item.Id);
}
private UniqueItemStack(UniqueItemStack from)
{
_items = from._items;
@ -91,9 +90,10 @@ public class UniqueItemStack : IItemStack
if (value < 0) value = Quantity;
var result = new UniqueItemStack(PickItem()!);
//Calculate the amount left to take out
//计算剩余的要取出的数量
var restToMove = Math.Min(value - 1, Quantity);
for (int i = 0; i < restToMove; i++)
for (var i = 0; i < restToMove; i++)
{
result.AddItem(PickItem()!);
}

View File

@ -1,5 +1,3 @@
using System.Collections.Generic;
using ColdMint.scripts.debug;
using ColdMint.scripts.projectile;
using ColdMint.scripts.utils;

View File

@ -3,8 +3,6 @@ using System;
using ColdMint.scripts.camp;
using ColdMint.scripts.character;
using ColdMint.scripts.damage;
using ColdMint.scripts.inventory;
using Godot;
namespace ColdMint.scripts.item.weapon;
@ -116,7 +114,7 @@ public abstract partial class WeaponTemplate : RigidBody2D, IItem
//If it leaves the ground or walls.
//如果离开了地面或墙壁。
if (node is TileMap tileMap)
if (node is TileMap)
{
_tileMapNumber--;
if (_tileMapNumber == 0)
@ -141,7 +139,7 @@ public abstract partial class WeaponTemplate : RigidBody2D, IItem
return;
}
if (node is TileMap tileMap)
if (node is TileMap)
{
_tileMapNumber++;
EnableContactInjury = false;

View File

@ -1,5 +1,4 @@
using System.Threading.Tasks;
using ColdMint.scripts.map.events;
using ColdMint.scripts.map.events;
using Godot;
namespace ColdMint.scripts.loader.uiLoader;

View File

@ -1,5 +1,4 @@
using ColdMint.scripts.character;
using ColdMint.scripts.debug;
using ColdMint.scripts.map.events;
using ColdMint.scripts.utils;
using Godot;

View File

@ -2,11 +2,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using ColdMint.scripts.debug;
using ColdMint.scripts.inventory;
using ColdMint.scripts.item;
using ColdMint.scripts.item.weapon;
using Godot;
using Packsack = ColdMint.scripts.item.Packsack;
namespace ColdMint.scripts.utils;