mirror of
https://github.com/libretro/desmume2014.git
synced 2026-11-08 08:09:06 -10:00
242 lines
7.4 KiB
C++
242 lines
7.4 KiB
C++
/*
|
|
Copyright (C) 2009-2010 DeSmuME team
|
|
|
|
This file is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This file is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef LUA_SCRIPT_H
|
|
#define LUA_SCRIPT_H
|
|
|
|
#include "emu-types.h"
|
|
|
|
#if defined(WIN32) && !defined(WXPORT)
|
|
#include <winsock2.h>
|
|
#include <windows.h>
|
|
#include "resource.h"
|
|
#endif
|
|
|
|
void OpenLuaContext(int uid, void(*print)(int uid, const char* str) = 0, void(*onstart)(int uid) = 0, void(*onstop)(int uid, bool statusOK) = 0);
|
|
void RunLuaScriptFile(int uid, const char* filename);
|
|
void StopLuaScript(int uid);
|
|
void RequestAbortLuaScript(int uid, const char* message = 0);
|
|
void CloseLuaContext(int uid);
|
|
bool AnyLuaActive();
|
|
|
|
enum LuaCallID
|
|
{
|
|
LUACALL_BEFOREEMULATION,
|
|
LUACALL_AFTEREMULATION,
|
|
LUACALL_AFTEREMULATIONGUI,
|
|
LUACALL_BEFOREEXIT,
|
|
LUACALL_BEFORESAVE,
|
|
LUACALL_AFTERLOAD,
|
|
LUACALL_ONSTART,
|
|
LUACALL_ONINITMENU,
|
|
|
|
LUACALL_SCRIPT_HOTKEY_1,
|
|
LUACALL_SCRIPT_HOTKEY_2,
|
|
LUACALL_SCRIPT_HOTKEY_3,
|
|
LUACALL_SCRIPT_HOTKEY_4,
|
|
LUACALL_SCRIPT_HOTKEY_5,
|
|
LUACALL_SCRIPT_HOTKEY_6,
|
|
LUACALL_SCRIPT_HOTKEY_7,
|
|
LUACALL_SCRIPT_HOTKEY_8,
|
|
LUACALL_SCRIPT_HOTKEY_9,
|
|
LUACALL_SCRIPT_HOTKEY_10,
|
|
LUACALL_SCRIPT_HOTKEY_11,
|
|
LUACALL_SCRIPT_HOTKEY_12,
|
|
LUACALL_SCRIPT_HOTKEY_13,
|
|
LUACALL_SCRIPT_HOTKEY_14,
|
|
LUACALL_SCRIPT_HOTKEY_15,
|
|
LUACALL_SCRIPT_HOTKEY_16,
|
|
|
|
LUACALL_COUNT
|
|
};
|
|
void CallRegisteredLuaFunctions(LuaCallID calltype);
|
|
|
|
enum LuaMemHookType
|
|
{
|
|
LUAMEMHOOK_WRITE,
|
|
LUAMEMHOOK_READ,
|
|
LUAMEMHOOK_EXEC,
|
|
LUAMEMHOOK_WRITE_SUB,
|
|
LUAMEMHOOK_READ_SUB,
|
|
LUAMEMHOOK_EXEC_SUB,
|
|
|
|
LUAMEMHOOK_COUNT
|
|
};
|
|
void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType);
|
|
|
|
struct LuaSaveData
|
|
{
|
|
LuaSaveData() { recordList = 0; }
|
|
~LuaSaveData() { ClearRecords(); }
|
|
|
|
struct Record
|
|
{
|
|
unsigned int key; // crc32
|
|
unsigned int size; // size of data
|
|
unsigned char* data;
|
|
Record* next;
|
|
};
|
|
|
|
Record* recordList;
|
|
|
|
void SaveRecord(int uid, unsigned int key); // saves Lua stack into a record and pops it
|
|
void LoadRecord(int uid, unsigned int key, unsigned int itemsToLoad) const; // pushes a record's data onto the Lua stack
|
|
void SaveRecordPartial(int uid, unsigned int key, int idx); // saves part of the Lua stack (at the given index) into a record and does NOT pop anything
|
|
|
|
void ExportRecords(void* file) const; // writes all records to an already-open file
|
|
void ImportRecords(void* file); // reads records from an already-open file
|
|
void ClearRecords(); // deletes all record data
|
|
|
|
private:
|
|
// disallowed, it's dangerous to call this
|
|
// (because the memory the destructor deletes isn't refcounted and shouldn't need to be copied)
|
|
// so pass LuaSaveDatas by reference and this should never get called
|
|
LuaSaveData(const LuaSaveData& copy) {}
|
|
};
|
|
void CallRegisteredLuaSaveFunctions(int savestateNumber, LuaSaveData& saveData);
|
|
void CallRegisteredLuaLoadFunctions(int savestateNumber, const LuaSaveData& saveData);
|
|
|
|
#if defined(WIN32) && !defined(WXPORT)
|
|
typedef HMENU PlatformMenu; // hMenu
|
|
typedef UINT PlatformMenuItem; // menuId
|
|
#define MAX_MENU_COUNT (IDC_LUAMENU_RESERVE_END - IDC_LUAMENU_RESERVE_START + 1)
|
|
#else
|
|
// TODO: define appropriate types for menu
|
|
typedef void* PlatformMenu;
|
|
typedef u32 PlatformMenuItem;
|
|
#define MAX_MENU_COUNT 0
|
|
#endif
|
|
void CallRegisteredLuaMenuHandlers(PlatformMenuItem menuItem);
|
|
|
|
void StopAllLuaScripts();
|
|
void RestartAllLuaScripts();
|
|
void EnableStopAllLuaScripts(bool enable);
|
|
void DontWorryLua();
|
|
|
|
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
// the purpose of this structure is to provide a way of
|
|
// QUICKLY determining whether a memory address range has a hook associated with it,
|
|
// with a bias toward fast rejection because the majority of addresses will not be hooked.
|
|
// (it must not use any part of Lua or perform any per-script operations,
|
|
// otherwise it would definitely be too slow.)
|
|
// calculating the regions when a hook is added/removed may be slow,
|
|
// but this is an intentional tradeoff to obtain a high speed of checking during later execution
|
|
struct TieredRegion
|
|
{
|
|
template<unsigned int maxGap>
|
|
struct Region
|
|
{
|
|
struct Island
|
|
{
|
|
unsigned int start;
|
|
unsigned int end;
|
|
FORCEINLINE bool Contains(unsigned int address, int size) const { return address < end && address+size > start; }
|
|
};
|
|
std::vector<Island> islands;
|
|
|
|
void Calculate(const std::vector<unsigned int>& bytes)
|
|
{
|
|
islands.clear();
|
|
|
|
unsigned int lastEnd = ~0;
|
|
|
|
std::vector<unsigned int>::const_iterator iter = bytes.begin();
|
|
std::vector<unsigned int>::const_iterator end = bytes.end();
|
|
for(; iter != end; ++iter)
|
|
{
|
|
unsigned int addr = *iter;
|
|
if(addr < lastEnd || addr > lastEnd + (long long)maxGap)
|
|
{
|
|
islands.push_back(Island());
|
|
islands.back().start = addr;
|
|
}
|
|
islands.back().end = addr+1;
|
|
lastEnd = addr+1;
|
|
}
|
|
}
|
|
|
|
bool Contains(unsigned int address, int size) const
|
|
{
|
|
typename std::vector<Island>::const_iterator iter = islands.begin();
|
|
typename std::vector<Island>::const_iterator end = islands.end();
|
|
for(; iter != end; ++iter)
|
|
if(iter->Contains(address, size))
|
|
return true;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
Region<0xFFFFFFFF> broad;
|
|
Region<0x1000> mid;
|
|
Region<0> narrow;
|
|
|
|
void Calculate(std::vector<unsigned int>& bytes)
|
|
{
|
|
std::sort(bytes.begin(), bytes.end());
|
|
|
|
broad.Calculate(bytes);
|
|
mid.Calculate(bytes);
|
|
narrow.Calculate(bytes);
|
|
}
|
|
|
|
TieredRegion()
|
|
{
|
|
std::vector<unsigned int> somevector;
|
|
Calculate(somevector);
|
|
}
|
|
|
|
FORCEINLINE int NotEmpty()
|
|
{
|
|
return broad.islands.size();
|
|
}
|
|
|
|
// note: it is illegal to call this if NotEmpty() returns 0
|
|
FORCEINLINE bool Contains(unsigned int address, int size)
|
|
{
|
|
return broad.islands[0].Contains(address,size) &&
|
|
mid.Contains(address,size) &&
|
|
narrow.Contains(address,size);
|
|
}
|
|
};
|
|
extern TieredRegion hookedRegions [LUAMEMHOOK_COUNT];
|
|
|
|
void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType);
|
|
|
|
FORCEINLINE void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
|
|
{
|
|
// performance critical! (called VERY frequently)
|
|
// I suggest timing a large number of calls to this function in Release if you change anything in here,
|
|
// before and after, because even the most innocent change can make it become 30% to 400% slower.
|
|
// a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set.
|
|
// (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter case)
|
|
if(hookedRegions[hookType].NotEmpty())
|
|
{
|
|
//if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000))
|
|
// address |= 0xFF0000; // gens: account for mirroring of RAM
|
|
if(hookedRegions[hookType].Contains(address, size))
|
|
CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType); // something has hooked this specific address
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|
|
|