Rewrote get/set_proto_data functions in C++ and added an auto-extend mechanism for proto loading limit (from Mr.Stalin)

Replaced ProtoProcessingLimit with LoadProtoMaxLimit option.
Added more definitions to define_extra.h and reformatted sfall.h a bit.
This commit is contained in:
NovaRain
2018-10-07 10:30:59 +08:00
parent 6796dc1012
commit e6d958a83b
9 changed files with 139 additions and 143 deletions
+4 -4
View File
@@ -347,6 +347,10 @@ CorpseLineOfFireFix=0
;Set to 1 (or some higher number if needed, the maximum is 127) to prevent 100% CPU use
ProcessorIdle=-1
;Set a number of how many protos of a type can be loaded into memory at once (valid range: 512..4096)
;Set to -1 to let set_proto_data script function automatically increase the limit when needed
LoadProtoMaxLimit=-1
;Set to 1 if using the hero appearance mod
EnableHeroAppearanceMod=0
@@ -549,10 +553,6 @@ ExplosionsEmitLight=0
;MovieTimer_artimer3=270
;MovieTimer_artimer4=360
;Uncomment the next line to change how many protos the engine can process at once (valid range: 512..16384)
;Set to 1024 or some higher number to avoid some glitches with scripts that will process a large number of protos
;ProtoProcessingLimit=512
;Set to 1 to enable the new arrays behavior
;Set to 0 for backward compatibility with pre-3.4 scripts
arraysBehavior=1
+25 -9
View File
@@ -10,6 +10,12 @@
#define OBJ_TYPE_MISC (5)
#define OBJ_TYPE_SPATIAL (6)
#define WEAPON_TYPE_NONE (0)
#define WEAPON_TYPE_UNARMED (1)
#define WEAPON_TYPE_MELEE (2)
#define WEAPON_TYPE_THROWN (3)
#define WEAPON_TYPE_GUNS (4)
/* Item Common Flags */
#define HIDDEN_ITEM 134217728 // 0x08000000 - Hidden Item
@@ -21,14 +27,14 @@
#define WEAPON_2HAND 512 // 0x00000200 - 2Hnd (weapon is two-handed)
#define ATKMODE_PRI_NONE 0
#define ATKMODE_PRI_PUNCH 1
#define ATKMODE_PRI_KICK 2
#define ATKMODE_PRI_SWING 3
#define ATKMODE_PRI_THRUST 4
#define ATKMODE_PRI_THROW 5
#define ATKMODE_PRI_SINGLE 6
#define ATKMODE_PRI_BURST 7
#define ATKMODE_PRI_FLAME 8
#define ATKMODE_PRI_PUNCH 1 // 0001
#define ATKMODE_PRI_KICK 2 // 0010
#define ATKMODE_PRI_SWING 3 // 0011
#define ATKMODE_PRI_THRUST 4 // 0100
#define ATKMODE_PRI_THROW 5 // 0101
#define ATKMODE_PRI_SINGLE 6 // 0110
#define ATKMODE_PRI_BURST 7 // 0111
#define ATKMODE_PRI_FLAME 8 // 1000
#define ATKMODE_SEC_NONE 0
#define ATKMODE_SEC_PUNCH 16 // 0x00000010
#define ATKMODE_SEC_KICK 32 // 0x00000020
@@ -101,15 +107,21 @@
// offsets for get_proto_data
#define PROTO_PID (1)
#define PROTO_TEXTID (4)
#define PROTO_FID (8)
// items
#define PROTO_IT_LDIST (12)
#define PROTO_IT_LINT (16)
#define PROTO_IT_FLAG (20)
#define PROTO_IT_FLAGS (24)
#define PROTO_IT_SCRIPTID (28)
#define PROTO_IT_TYPE (32)
#define PROTO_IT_MATERIAL (108)
#define PROTO_IT_SIZE (112)
#define PROTO_IT_WEIGHT (116)
#define PROTO_IT_COST (120)
#define PROTO_IT_INV_FID (124)
#define PROTO_IT_SOUND (128) // byte
// weapons
#define PROTO_WP_ANIM (36)
@@ -187,7 +199,11 @@
#define PROTO_DR_ADDICT_DELAY (100)
// critters
#define PROTO_CR_FLAGS (32)
#define PROTO_CR_LDIST (20)
#define PROTO_CR_LINT (24)
#define PROTO_CR_FLAG (28)
#define PROTO_CR_FLAGS (32) // Critter Flags
#define PROTO_CR_SCRIPTID (36)
#define PROTO_CR_HEAD_FID (40)
#define PROTO_CR_AI_PACKET (44)
#define PROTO_CR_TEAM_NUM (48)
+42 -42
View File
@@ -221,45 +221,45 @@
#define party_member_list_all party_member_list(1)
#define attack_is_aimed sfall_func0("attack_is_aimed")
#define car_gas_amount sfall_func0("car_gas_amount")
#define create_win(winName, x, y, w, h) sfall_func5("create_win", winName, x, y, w, h)
#define create_win_flag(winName, x, y, w, h, flag) sfall_func6("create_win", winName, x, y, w, h, flag)
#define critter_inven_obj2(obj, type) sfall_func2("critter_inven_obj2", obj, type)
#define dialog_message(text) sfall_func1("dialog_message", text)
#define display_stats sfall_func0("display_stats")
#define exec_map_update_scripts sfall_func0("exec_map_update_scripts")
#define floor2(value) sfall_func1("floor2", value)
#define get_can_rest_on_map(map, elev) sfall_func2("get_can_rest_on_map", map, elev)
#define get_current_inven_size(obj) sfall_func1("get_current_inven_size", obj)
#define get_cursor_mode sfall_func0("get_cursor_mode")
#define get_flags(obj) sfall_func1("get_flags", obj)
#define get_ini_section(file, sect) sfall_func2("get_ini_section", file, sect)
#define get_ini_sections(file) sfall_func1("get_ini_sections", file)
#define get_map_enter_position sfall_func0("get_map_enter_position")
#define get_outline(obj) sfall_func1("get_outline", obj)
#define get_string_pointer(text) sfall_func1("get_string_pointer", text)
#define intface_hide sfall_func0("intface_hide")
#define intface_is_hidden sfall_func0("intface_is_hidden")
#define intface_redraw sfall_func0("intface_redraw")
#define intface_show sfall_func0("intface_show")
#define inventory_redraw(invSide) sfall_func1("inventory_redraw", invSide)
#define item_weight(obj) sfall_func1("item_weight", obj)
#define lock_is_jammed(obj) sfall_func1("lock_is_jammed", obj)
#define outlined_object sfall_func0("outlined_object")
#define real_dude_obj sfall_func0("real_dude_obj")
#define set_can_rest_on_map(map, elev, value) sfall_func3("set_can_rest_on_map", map, elev, value)
#define set_car_intface_art(artIndex) sfall_func1("set_car_intface_art", artIndex)
#define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode)
#define set_dude_obj(critter) sfall_func1("set_dude_obj", critter)
#define set_flags(obj, flags) sfall_func2("set_flags", obj, flags)
#define set_iface_tag_text(tag, text, color) sfall_func3("set_iface_tag_text", tag, text, color)
#define set_ini_setting(setting, value) sfall_func2("set_ini_setting", setting, value)
#define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot)
#define set_outline(obj, color) sfall_func2("set_outline", obj, color)
#define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time)
#define set_rest_mode(mode) sfall_func1("set_rest_mode", mode)
#define set_unjam_locks_time(time) sfall_func1("set_unjam_locks_time", time)
#define spatial_radius(obj) sfall_func1("spatial_radius", obj)
#define tile_refresh_display sfall_func0("tile_refresh_display")
#define unjam_lock(obj) sfall_func1("unjam_lock", obj)
#define attack_is_aimed sfall_func0("attack_is_aimed")
#define car_gas_amount sfall_func0("car_gas_amount")
#define create_win(winName, x, y, w, h) sfall_func5("create_win", winName, x, y, w, h)
#define create_win_flag(winName, x, y, w, h, flag) sfall_func6("create_win", winName, x, y, w, h, flag)
#define critter_inven_obj2(obj, type) sfall_func2("critter_inven_obj2", obj, type)
#define dialog_message(text) sfall_func1("dialog_message", text)
#define display_stats sfall_func0("display_stats")
#define exec_map_update_scripts sfall_func0("exec_map_update_scripts")
#define floor2(value) sfall_func1("floor2", value)
#define get_can_rest_on_map(map, elev) sfall_func2("get_can_rest_on_map", map, elev)
#define get_current_inven_size(obj) sfall_func1("get_current_inven_size", obj)
#define get_cursor_mode sfall_func0("get_cursor_mode")
#define get_flags(obj) sfall_func1("get_flags", obj)
#define get_ini_section(file, sect) sfall_func2("get_ini_section", file, sect)
#define get_ini_sections(file) sfall_func1("get_ini_sections", file)
#define get_map_enter_position sfall_func0("get_map_enter_position")
#define get_outline(obj) sfall_func1("get_outline", obj)
#define get_string_pointer(text) sfall_func1("get_string_pointer", text)
#define intface_hide sfall_func0("intface_hide")
#define intface_is_hidden sfall_func0("intface_is_hidden")
#define intface_redraw sfall_func0("intface_redraw")
#define intface_show sfall_func0("intface_show")
#define inventory_redraw(invSide) sfall_func1("inventory_redraw", invSide)
#define item_weight(obj) sfall_func1("item_weight", obj)
#define lock_is_jammed(obj) sfall_func1("lock_is_jammed", obj)
#define outlined_object sfall_func0("outlined_object")
#define real_dude_obj sfall_func0("real_dude_obj")
#define set_can_rest_on_map(map, elev, value) sfall_func3("set_can_rest_on_map", map, elev, value)
#define set_car_intface_art(artIndex) sfall_func1("set_car_intface_art", artIndex)
#define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode)
#define set_dude_obj(critter) sfall_func1("set_dude_obj", critter)
#define set_flags(obj, flags) sfall_func2("set_flags", obj, flags)
#define set_iface_tag_text(tag, text, color) sfall_func3("set_iface_tag_text", tag, text, color)
#define set_ini_setting(setting, value) sfall_func2("set_ini_setting", setting, value)
#define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot)
#define set_outline(obj, color) sfall_func2("set_outline", obj, color)
#define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time)
#define set_rest_mode(mode) sfall_func1("set_rest_mode", mode)
#define set_unjam_locks_time(time) sfall_func1("set_unjam_locks_time", time)
#define spatial_radius(obj) sfall_func1("spatial_radius", obj)
#define tile_refresh_display sfall_func0("tile_refresh_display")
#define unjam_lock(obj) sfall_func1("unjam_lock", obj)
+33 -1
View File
@@ -26,6 +26,7 @@ namespace sfall
{
static int unjamTimeState;
static int maxCountProto = 512;
void Objects::SetAutoUnjamLockTime(DWORD time) {
if (!unjamTimeState) {
@@ -54,10 +55,41 @@ void RestoreObjUnjamAllLocks() {
}
}
static void __declspec(naked) proto_ptr_hack() {
__asm {
mov ecx, maxCountProto;
cmp ecx, 4096;
jae skip;
cmp eax, ecx;
jb end;
add ecx, 256;
mov maxCountProto, ecx;
skip:
cmp eax, ecx;
end:
retn;
}
}
void Objects::LoadProtoAutoMaxLimit() {
if (maxCountProto != -1) {
MakeCall(0x4A21B2, proto_ptr_hack);
}
}
void Objects::init() {
LoadGameHook::OnGameReset() += [] () {
LoadGameHook::OnGameReset() += []() {
RestoreObjUnjamAllLocks();
};
int maxlimit = GetConfigInt("Misc", "LoadProtoMaxLimit", -1);
if (maxlimit != -1) {
maxCountProto = -1;
if (maxlimit > 512) {
if (maxlimit > 4096) maxlimit = 4096;
SafeWrite32(0x4A21B3, maxlimit);
}
}
}
}
+1
View File
@@ -11,6 +11,7 @@ public:
void init();
static void SetAutoUnjamLockTime(DWORD time);
static void LoadProtoAutoMaxLimit();
};
}
-3
View File
@@ -661,9 +661,6 @@ void ScriptExtender::init() {
}
modifiedIni = GetConfigInt("Main", "ModifiedIni", 0);
// increase the processing limit of proto_ptr_ engine function
SimplePatch<DWORD>(0x4A21B3, "Misc", "ProtoProcessingLimit", 512, 512, 16384);
arraysBehavior = GetConfigInt("Misc", "arraysBehavior", 1);
if (arraysBehavior > 0) {
arraysBehavior = 1; // only 1 and 0 allowed at this time
+22 -75
View File
@@ -27,6 +27,7 @@
#include "..\..\Knockback.h"
#include "..\..\MiscPatches.h"
#include "..\..\Movies.h"
#include "..\..\Objects.h"
#include "..\..\PlayerModel.h"
#include "..\..\ScriptExtender.h"
#include "..\..\Stats.h"
@@ -1145,84 +1146,30 @@ void __declspec(naked) op_nb_create_char() {
}
}
void __declspec(naked) op_get_proto_data() {
__asm {
pushad;
sub esp, 4;
mov ebp, eax;
call fo::funcoffs::interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call fo::funcoffs::interpretPopLong_;
mov ecx, eax;
mov eax, ebp;
call fo::funcoffs::interpretPopShort_;
mov esi, eax;
mov eax, ebp;
call fo::funcoffs::interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz fail;
cmp si, VAR_TYPE_INT;
jnz fail;
mov edx, esp;
call fo::funcoffs::proto_ptr_;
mov eax, [esp];
test eax, eax;
jz fail;
mov edx, [eax+ecx/**4*/];
jmp end;
fail:
xor edx, edx;
dec edx;
end:
mov eax, ebp;
call fo::funcoffs::interpretPushLong_;
mov eax, ebp;
mov edx, VAR_TYPE_INT;
call fo::funcoffs::interpretPushShort_;
add esp, 4;
popad;
retn;
void sf_get_proto_data(OpcodeContext& ctx) {
fo::Proto* protoPtr;
int pid = ctx.arg(0).rawValue();
int result = fo::func::proto_ptr(pid, &protoPtr);
if (result != -1) {
result = *(long*)((BYTE*)protoPtr + ctx.arg(1).rawValue());
} else {
ctx.printOpcodeError("get_proto_data() - failed to load a prototype id: %d", pid);
}
ctx.setReturn(result);
}
void __declspec(naked) op_set_proto_data() {
__asm {
pushad;
sub esp, 4;
mov ebp, eax;
call fo::funcoffs::interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call fo::funcoffs::interpretPopLong_;
mov ecx, eax;
mov eax, ebp;
call fo::funcoffs::interpretPopShort_;
mov esi, eax;
mov eax, ebp;
call fo::funcoffs::interpretPopLong_;
mov ebx, eax;
mov eax, ebp;
call fo::funcoffs::interpretPopShort_;
xchg eax, ebp;
call fo::funcoffs::interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz end;
cmp si, VAR_TYPE_INT;
jnz end;
cmp bp, VAR_TYPE_INT;
jnz end;
//mov eax, [eax+0x64];
mov edx, esp;
call fo::funcoffs::proto_ptr_;
mov eax, [esp];
test eax, eax;
jz end;
mov [eax+ebx/**4*/], ecx;
end:
add esp, 4;
popad;
retn;
static bool protoMaxLimitPatch = false;
void sf_set_proto_data(OpcodeContext& ctx) {
fo::Proto* protoPtr;
int pid = ctx.arg(0).rawValue();
if (fo::func::proto_ptr(pid, &protoPtr) != -1) {
*(long*)((BYTE*)protoPtr + ctx.arg(1).rawValue()) = ctx.arg(2).rawValue();
if (!protoMaxLimitPatch) {
Objects::LoadProtoAutoMaxLimit();
protoMaxLimitPatch = true;
}
} else {
ctx.printOpcodeError("set_proto_data() - failed to load a prototype id: %d", pid);
}
}
+2 -2
View File
@@ -109,9 +109,9 @@ void __declspec() op_set_palette();
//numbers subgame functions
void __declspec() op_nb_create_char();
void __declspec() op_get_proto_data();
void sf_get_proto_data(OpcodeContext&);
void __declspec() op_set_proto_data();
void sf_set_proto_data(OpcodeContext&);
void __declspec() op_hero_select_win() ;
+10 -7
View File
@@ -90,6 +90,8 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x201, "fs_pos", sf_fs_pos, 1, true, {ARG_INT}},
{0x202, "fs_seek", sf_fs_seek, 2, false, {ARG_INT, ARG_INT}},
{0x203, "fs_resize", sf_fs_resize, 2, false, {ARG_INT, ARG_INT}},
{0x204, "get_proto_data", sf_get_proto_data, 2, true, {ARG_INT, ARG_INT}},
{0x205, "set_proto_data", sf_set_proto_data, 3, false, {ARG_INT, ARG_INT, ARG_INT}},
{0x207, "register_hook", sf_register_hook, 1, false, {ARG_INT}},
{0x208, "fs_write_bstring", sf_fs_write_bstring, 2, false, {ARG_INT, ARG_STRING}},
{0x209, "fs_read_byte", sf_fs_read_byte, 1, true, {ARG_INT}},
@@ -188,7 +190,7 @@ void InitOpcodeInfoTable() {
// Default handler for Sfall Opcodes.
// Searches current opcode in Opcode Info table and executes the appropriate handler.
void __stdcall defaultOpcodeHandlerStdcall(fo::Program* program, DWORD opcodeOffset) {
void __fastcall defaultOpcodeHandlerCall(fo::Program* program, DWORD opcodeOffset) {
int opcode = opcodeOffset / 4;
auto iter = opcodeInfoMap.find(opcode);
if (iter != opcodeInfoMap.end()) {
@@ -203,11 +205,14 @@ void __stdcall defaultOpcodeHandlerStdcall(fo::Program* program, DWORD opcodeOff
// Default handler for Sfall opcodes (naked function for integration with the engine).
void __declspec(naked) defaultOpcodeHandler() {
__asm {
pushad;
push edx;
push eax;
call defaultOpcodeHandlerStdcall;
popad;
push ecx;
push edx;
mov ecx, eax; // ecx - program
call defaultOpcodeHandlerCall; // edx - opcodeOffset
pop edx;
pop ecx;
pop eax;
retn;
}
}
@@ -365,8 +370,6 @@ void InitNewOpcodes() {
opcodes[0x1f4] = op_set_script;
opcodes[0x1f6] = op_nb_create_char;
opcodes[0x204] = op_get_proto_data;
opcodes[0x205] = op_set_proto_data;
opcodes[0x206] = op_set_self;
opcodes[0x213] = op_hero_select_win;
opcodes[0x214] = op_set_hero_race;