• Крафт в StarsOne

    Перенесена Статьи и видео unity dnspy блог
    1
    8
    0 Голоса
    1 Сообщения
    82 Просмотры
    MasterGHM
    В оригинале, если нет всех компонентов рецепта, то нельзя скрафтить вещь. Цель: скрафтить без компонетов по нажатию кнопки Игра на Unity и можно пробовать использовать в dnSpy модифицировать файл Assembly-CSharp.dll Открываем файлик и смотрим на классы связанные с крафтом Так находим кнопку, которая создаст указанное количество вещей крафта в CreateItem Задача скрафтить по имеющемуся рецепту любую вещь. Для этого я добавляю проверку количества вещей и удаляю лишний код. Под сполерами оригинальный и модифицированный код Модифицированный код using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using UnityEngine; public partial class Crafting : MonoBehaviour { public void CreateItem(int curCraft, int craftCount) { if (this.timeBreak >= 0.3f) { // Добавили одну вещь крафта if (craftCount == 0) { craftCount = 1; } if (craftCount != 0) { this.succes = true; CraftRecipe component = this.craftObjects[curCraft].GetComponent<CraftRecipe>(); // Здесь удалили код, который должен расходовать вещи из инвентаря // ... if (this.succes) { this.iks = this.craftObjects[curCraft].GetComponent<CraftRecipe>().countCreate * craftCount; for (int m = 0; m < this.craftObjects[curCraft].GetComponent<CraftRecipe>().countCreate * craftCount; m++) { this.emptyCell = Inventory.inv.FindItemForStack(this.craftObjects[curCraft].name); if (this.emptyCell >= 0) { if (Inventory.inv.items[this.emptyCell].stack + this.iks <= Inventory.inv.items[this.emptyCell].maxStack) { Inventory.inv.items[this.emptyCell].stack += this.iks; break; } this.iks -= Inventory.inv.items[this.emptyCell].maxStack - Inventory.inv.items[this.emptyCell].stack; Inventory.inv.items[this.emptyCell].stack = Inventory.inv.items[this.emptyCell].maxStack; } else { this.emptyCell = Inventory.inv.FindEmptyCell(); if (this.emptyCell >= 0) { this.cloneItem = Inventory.inv.CreateItem(this.craftObjects[curCraft]); if (this.cloneItem.maxStack >= this.iks) { this.cloneItem.stack = this.iks; Inventory.inv.items[this.emptyCell] = this.cloneItem; break; } this.cloneItem.stack = this.cloneItem.maxStack; this.iks -= this.cloneItem.maxStack; Inventory.inv.items[this.emptyCell] = this.cloneItem; } else { if (this.craftObjects[curCraft].GetComponent<Item>().maxStack >= this.iks) { PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.iks, this.craftObjects[curCraft].GetComponent<Item>().health); break; } PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.craftObjects[curCraft].GetComponent<Item>().maxStack, this.craftObjects[curCraft].GetComponent<Item>().health); this.iks -= this.craftObjects[curCraft].GetComponent<Item>().maxStack; } new WaitForEndOfFrame(); } } } } this.timeBreak = 0f; } } } Оригинальный public void CreateItem(int curCraft, int craftCount) { if (this.timeBreak >= 0.3f) { if (craftCount != 0) { this.succes = true; CraftRecipe component = this.craftObjects[curCraft].GetComponent<CraftRecipe>(); int[] array = new int[7]; int[] array2 = new int[7]; for (int i = 0; i < 7; i++) { if (this.succes && component.ingredients[i] != null) { array2[i] = component.countIngredients[i]; if (array2[i] <= 0) { array2[i] = 1; } array2[i] *= craftCount; for (int j = 0; j < Inventory.inv.items.Length; j++) { if (Inventory.inv.items[j] != null && component.ingredients[i].name == Inventory.inv.items[j].prefName) { array[i] += Inventory.inv.items[j].stack; } } if (array[i] < array2[i]) { this.succes = false; } } } if (this.succes) { for (int k = 0; k < 7; k++) { if (component.ingredients[k] != null) { for (int l = 0; l < Inventory.inv.items.Length; l++) { if (Inventory.inv.items[l] != null && array2[k] > 0 && component.ingredients[k].name == Inventory.inv.items[l].prefName) { this.iks = Inventory.inv.items[l].stack; Inventory.inv.items[l].stack -= array2[k]; array2[k] -= this.iks; if (array2[k] <= 0) { break; } } } } } this.iks = this.craftObjects[curCraft].GetComponent<CraftRecipe>().countCreate * craftCount; for (int m = 0; m < this.craftObjects[curCraft].GetComponent<CraftRecipe>().countCreate * craftCount; m++) { this.emptyCell = Inventory.inv.FindItemForStack(this.craftObjects[curCraft].name); if (this.emptyCell >= 0) { if (Inventory.inv.items[this.emptyCell].stack + this.iks <= Inventory.inv.items[this.emptyCell].maxStack) { Inventory.inv.items[this.emptyCell].stack += this.iks; break; } this.iks -= Inventory.inv.items[this.emptyCell].maxStack - Inventory.inv.items[this.emptyCell].stack; Inventory.inv.items[this.emptyCell].stack = Inventory.inv.items[this.emptyCell].maxStack; } else { this.emptyCell = Inventory.inv.FindEmptyCell(); if (this.emptyCell >= 0) { this.cloneItem = Inventory.inv.CreateItem(this.craftObjects[curCraft]); if (this.cloneItem.maxStack >= this.iks) { this.cloneItem.stack = this.iks; Inventory.inv.items[this.emptyCell] = this.cloneItem; break; } this.cloneItem.stack = this.cloneItem.maxStack; this.iks -= this.cloneItem.maxStack; Inventory.inv.items[this.emptyCell] = this.cloneItem; } else { if (this.craftObjects[curCraft].GetComponent<Item>().maxStack >= this.iks) { PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.iks, this.craftObjects[curCraft].GetComponent<Item>().health); break; } PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.craftObjects[curCraft].GetComponent<Item>().maxStack, this.craftObjects[curCraft].GetComponent<Item>().health); this.iks -= this.craftObjects[curCraft].GetComponent<Item>().maxStack; } new WaitForEndOfFrame(); } } } } this.timeBreak = 0f; } } Изменяем весь класс или метов в этом окне Если выводит ошибки при компяляции, то скачиваем IlSpy и его код вставляем в код в dnSpy. Или качаем DnSpy 3.2.0 или ранее Изменения сохраняем в модуль, запускаем игру и крафтим. Получить все рецепты (не проверял правда, попробуйте если хотите) Вещи не ломаются. Убрать отнятие "здоровья" у вещи
  • [The Escapists 2 + Unity + dnSpy] Спавн итемов

    Перенесена Статьи и видео unity cheats dnspy csharp блог
    1
    2
    0 Голоса
    1 Сообщения
    88 Просмотры
    MasterGHM
    Спавн итемов удалось сделать через dnSpy При клике на любой предмет на меню крафта он создается в инвентаре, а если там занято, то выкидывается на карту. Я переписал метод клика на рецепт, вот он оригинальный // Token: 0x060069FA RID: 27130 RVA: 0x00254874 File Offset: 0x00252A74 private void OnRecipeSlotClicked(int recipeSlotID) { if (recipeSlotID == this.m_CurrentClickedRecipeID) { if (!T17RewiredStandaloneInputModule.IsCurrentActiveModuleUsingController()) { this.m_CurrentClickedRecipeID = -1; } return; } if (!this.CheckHasItemsForRecipe(recipeSlotID)) { this.m_CurrentClickedRecipeID = -1; return; } CraftManager.Recipe recipeByID = CraftManager.GetInstance().GetRecipeByID(recipeSlotID); if (recipeByID != null && (!recipeByID.m_bHidden || recipeByID.m_bDiscovered)) { this.FillSlots(recipeSlotID); this.m_CurrentClickedRecipeID = recipeSlotID; return; } this.m_CurrentClickedRecipeID = -1; } На этот private void OnRecipeSlotClicked(int recipeSlotID) { int itemDataID = CraftManager.GetInstance().GetCurrentRecipes()[recipeSlotID].m_Product.m_ItemDataID; Character character = base.CurrentGamePlayer.GetComponent(); ItemManager.GetInstance().AssignItemRPC(character.m_NetView.ownerId, itemDataID, new ItemManager.ItemManagerEvent(this.OnStandingAnimItemSpawn), ref character.m_StandingStillEquipID, -1); } private void OnStandingAnimItemSpawn(Item item, int eventID) { if (base.CurrentGamePlayer.GetComponent().m_StandingStillEquipID == eventID) { Player player = base.CurrentGamePlayer; bool flag = false; if (player.GetEquippedItem() == null) { flag = player.SetEquippedItem(item, true, false, RPC_CallContexts.Master); } if (!flag) { item.DropItemInLevel(player, player.transform.position); } } } Для спавна заменить Assembly-CSharp.dll из архива, сделав копию предварительно Assembly-CSharp.rar
  • [dnSpy + Unity ] Пошаговая отладка

    Перенесена Статьи и видео unity dnspy decompile debug блог
    1
    5
    0 Голоса
    1 Сообщения
    627 Просмотры
    MasterGHM
    Эта статья позволит отлаживать игры на Unity в Runtime и при этом видеть декомпилированный код. Это, конечно, не для всех игр на Unity. Пошаговая отладка в dnSpy позволяет ставить брейкпоинты на C# код во время работы игры, перемещаться по коду, просматривать значения переменных. Сэкономит кучу времени при поиске и отладке игрового кода, Страница загрузки dnSpy Скачиваем dnSpy и все архивы с mono.dll файлами Unity-debugging-4.x-win32.zip Unity-debugging-4.x-win64.zip Unity-debugging-win32.zip Unity-debugging-win64.zip Смотрим свойства exe файла игры и определяем по нему версию Unity. Например, "Версия продукта 5.5.0.3120186" или версия "файла 5.50.39994" может указывать на версию Unity 5.5. Определяем разрядность приложения через Process Explorer Т.к. версия Unity 5.5 и приложение 32 разрядное, то открываем Unity-debugging-win32.zip ищем там версию Unity и заменяем mono.dll в директории игры Запускаем игру и dnSpy x86 (игра 32 разрядная поэтому x86). Открываем файл "...\Managed\Assembly-CSharp.dll" Запускаем отладку нажав F5 или кнопку Play Настраиваем соединение и жмем ок Ставим брейкпоинты, смотрим перемененные, перемещаемся по коду, пишем свой код и так далее После изменения кода, нужно перезаписать модуль предварительно сохранив его О других способах подключения пошаговой отладки есть на английском руководство. Как работать в пошаговой отладке Работать можно почти также как и в Cheat Engine в пошаговой отладке или в среде разработки программ. Начать стоит с обзора названия пространств имен, названия классов, методов и полей, Названия могут подсказать логическую связь с читом, который хотим сделать. Стоит обратить внимание на такие названия как "IsPlayer, Player, Character, CharacterController, MainCharacter, Health, Inventory, Craft" и другие. Чтобы не искать вручную можно задействовать поиск сборкам. Поиск стандартного тега "Player" в виде в строки кода (в Unity выше версии 5.0) или свойства "IsPlayer" может помочь найти игрока или отличить от чужих. Важно представлять иерархию игровых объектов, которую мы не видим в dnSpy. Программист работая в Unity видит это окошко много лет и эту иерархию всегда представляет смотря на скрипты в dnSpy Скрипты наследники от MonoBehavior могут находиться на игровом объекте и могут работать как с ним так и с другими объектами. Получается такая штука, что игровой объект всегда имеет Transform компонент с полями позиций, углами и scale. Классы Transform и GameObject самые основные. Методами этих классов можно разместить объект в мире, создать или удалить его. В идеале удалив объект со сцены не должно быть никаких ошибок связанных с пустыми ссылками, потерей объекта. Также и клонировав объект, тоже не должно быть ошибок. Но не всегда так просто отспавнить игровой объект. Если это сделать методами UnityEngine, то другие классы ничего не будут знать о появлении игрового объекта. Нужно ставить брейкпоинт в функции Start или Awake в классе и трейсить по Shift+11 чтобы выйти на функцию разработчиков спавна этого GameObject. Функции Start или Awake (в классе наследника от MonoBehavior) срабатывают один раз при включении скрипта и инициализации. По ним можно выйти на строку кода, которая создает объекты в мире. Отдельно стоит сказать про количество скриптов. Практически в любой игре, которая мне попадалась в dnSpy много скриптов или очень много. Иногда и не будет понятных названий у типов (из-за обфускации). В любом случае при пошаговой отладке можно найти требующиеся участки кода для создания чита и использовать их по другой логике. Основные приемы В Update можно обновлять параметры только своего игрока. Например, в Character классе сделать сравнения в Update по IsPlayer свойству (если оно там есть) и у тебя за каждый кадр рендеринга будет максимум характеристик. В Update с классом Input можно считывать хоткеи. В Start и Awake можно подгружать свои ассеты с внутриигровым user interface. Код скриптов перед загрузкой ассетов должен быть внедрен через dnSpy Иерархию игровых объектов и инспектор, если очень нужно, то можно отрисовать в user interface. Обычно не требуется. (поищите по форуму в игрострое) В заключении Пока нет времени делать трейнер или таблицу на CE для включения опций в играх Unity. Для меня пока подходит способ через перезапись модуля в dnSpy вручную. Вместо трейнера можно сделать программу патчер, который будет проверять версию игры и перезаписывать модуль с возможностью вернуть оригинальный модуль