EQ2EMu/EQ2/source/common/opcodemgr.cpp
2020-07-29 20:53:25 -04:00

320 lines
8 KiB
C++

/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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 3 of the License, or
(at your option) any later version.
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "debug.h"
#include <stdio.h>
#include <string.h>
#include "opcodemgr.h"
//#include "debug.h"
#include "emu_opcodes.h"
#include "../common/Log.h"
#if defined(SHARED_OPCODES) && !defined(EQ2)
#include "EMuShareMem.h"
extern LoadEMuShareMemDLL EMuShareMemDLL;
#endif
#include <map>
#include <string>
using namespace std;
//#define DEBUG_TRANSLATE
OpcodeManager::OpcodeManager() {
loaded = false;
}
bool OpcodeManager::LoadOpcodesMap(map<string, uint16>* eq, OpcodeSetStrategy *s){
//do the mapping and store them in the shared memory array
bool ret = true;
EmuOpcode emu_op;
map<string, uint16>::iterator res;
//stupid enum wont let me ++ on it...
for(emu_op = (EmuOpcode)(0); emu_op < _maxEmuOpcode; emu_op=(EmuOpcode)(emu_op+1)) {
//get the name of this emu opcode
const char *op_name = OpcodeNames[emu_op];
if(op_name[0] == '\0') {
break;
}
//find the opcode in the file
res = eq->find(op_name);
if(res == eq->end()) {
LogWrite(OPCODE__WARNING, 1, "Opcode", "Opcode %s is missing from the opcodes table.", op_name);
s->Set(emu_op, 0xFFFF);
continue; //continue to give them a list of all missing opcodes
}
//ship the mapping off to shared mem.
s->Set(emu_op, res->second);
}
return ret;
}
bool OpcodeManager::LoadOpcodesFile(const char *filename, OpcodeSetStrategy *s) {
FILE *opf = fopen(filename, "r");
if(opf == NULL) {
LogWrite(OPCODE__ERROR, 0, "Opcode", "Unable to open opcodes file '%s'. Thats bad.", filename);
return(false);
}
map<string, uint16> eq;
//load the opcode file into eq, could swap in a nice XML parser here
char line[2048];
int lineno = 0;
uint16 curop;
while(!feof(opf)) {
lineno++;
line[0] = '\0'; //for blank line at end of file
if(fgets(line, sizeof(line), opf) == NULL)
break;
//ignore any line that dosent start with OP_
if(line[0] != 'O' || line[1] != 'P' || line[2] != '_')
continue;
char *num = line+3; //skip OP_
//look for the = sign
while(*num != '=' && *num != '\0') {
num++;
}
//make sure we found =
if(*num != '=') {
LogWrite(OPCODE__ERROR, 0, "Opcode", "Malformed opcode line at %s:%d\n", filename, lineno);
continue;
}
*num = '\0'; //null terminate the name
num++; //num should point to the opcode
//read the opcode
if(sscanf(num, "0x%hx", &curop) != 1) {
LogWrite(OPCODE__ERROR, 0, "Opcode", "Malformed opcode at %s:%d\n", filename, lineno);
continue;
}
//we have a name and our opcode... stick it in the map
eq[line] = curop;
}
fclose(opf);
return LoadOpcodesMap(&eq, s);
}
//convenience routines
const char *OpcodeManager::EmuToName(const EmuOpcode emu_op) {
return(OpcodeNames[emu_op]);
}
const char *OpcodeManager::EQToName(const uint16 eq_op) {
//first must resolve the eq op to an emu op
EmuOpcode emu_op = EQToEmu(eq_op);
return(OpcodeNames[emu_op]);
}
EmuOpcode OpcodeManager::NameSearch(const char *name) {
EmuOpcode emu_op;
//stupid enum wont let me ++ on it...
for(emu_op = (EmuOpcode)(0); emu_op < _maxEmuOpcode; emu_op=(EmuOpcode)(emu_op+1)) {
//get the name of this emu opcode
const char *op_name = OpcodeNames[emu_op];
if(!strcasecmp(op_name, name)) {
return(emu_op);
}
}
return(OP_Unknown);
}
RegularOpcodeManager::RegularOpcodeManager()
: MutableOpcodeManager()
{
emu_to_eq = NULL;
eq_to_emu = NULL;
EQOpcodeCount = 0;
EmuOpcodeCount = 0;
}
RegularOpcodeManager::~RegularOpcodeManager() {
safe_delete_array(emu_to_eq);
safe_delete_array(eq_to_emu);
}
bool RegularOpcodeManager::LoadOpcodes(map<string, uint16>* eq) {
NormalMemStrategy s;
s.it = this;
MOpcodes.lock();
loaded = true;
eq_to_emu = new EmuOpcode[MAX_EQ_OPCODE];
emu_to_eq = new uint16[_maxEmuOpcode];
EQOpcodeCount = MAX_EQ_OPCODE;
EmuOpcodeCount = _maxEmuOpcode;
//dont need to set eq_to_emu cause every element should get a value
memset(eq_to_emu, 0, sizeof(EmuOpcode)*MAX_EQ_OPCODE);
bool ret = LoadOpcodesMap(eq, &s);
MOpcodes.unlock();
return ret;
}
bool RegularOpcodeManager::LoadOpcodes(const char *filename) {
NormalMemStrategy s;
s.it = this;
MOpcodes.lock();
loaded = true;
eq_to_emu = new EmuOpcode[MAX_EQ_OPCODE];
emu_to_eq = new uint16[_maxEmuOpcode];
EQOpcodeCount = MAX_EQ_OPCODE;
EmuOpcodeCount = _maxEmuOpcode;
//dont need to set eq_to_emu cause every element should get a value
memset(eq_to_emu, 0, sizeof(EmuOpcode)*MAX_EQ_OPCODE);
bool ret = LoadOpcodesFile(filename, &s);
MOpcodes.unlock();
return ret;
}
bool RegularOpcodeManager::ReloadOpcodes(const char *filename) {
if(!loaded)
return(LoadOpcodes(filename));
NormalMemStrategy s;
s.it = this;
MOpcodes.lock();
memset(eq_to_emu, 0, sizeof(EmuOpcode)*MAX_EQ_OPCODE);
bool ret = LoadOpcodesFile(filename, &s);
MOpcodes.unlock();
return(ret);
}
uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
//opcode is checked for validity in GetEQOpcode
uint16 res;
MOpcodes.lock();
res = emu_to_eq[emu_op];
MOpcodes.unlock();
#ifdef _DEBUG_TRANSLATE
fprintf(stderr, "M Translate Emu %s (%d) to EQ 0x%.4x\n", OpcodeNames[emu_op], emu_op, res);
#endif
return(res);
}
EmuOpcode RegularOpcodeManager::EQToEmu(const uint16 eq_op) {
//opcode is checked for validity in GetEmuOpcode
//Disabled since current live EQ uses the entire uint16 bitspace for opcodes
// if(eq_op > MAX_EQ_OPCODE)
// return(OP_Unknown);
EmuOpcode res;
MOpcodes.lock();
res = eq_to_emu[eq_op];
MOpcodes.unlock();
#ifdef _DEBUG_TRANSLATE
fprintf(stderr, "M Translate EQ 0x%.4x to Emu %s (%d)\n", eq_op, OpcodeNames[res], res);
#endif
return(res);
}
void RegularOpcodeManager::SetOpcode(EmuOpcode emu_op, uint16 eq_op) {
//clear out old mapping
uint16 oldop = emu_to_eq[emu_op];
if(oldop != 0)
eq_to_emu[oldop] = OP_Unknown;
//use our strategy, since we have it
NormalMemStrategy s;
s.it = this;
s.Set(emu_op, eq_op);
}
void RegularOpcodeManager::NormalMemStrategy::Set(EmuOpcode emu_op, uint16 eq_op) {
if(uint32(emu_op) >= it->EmuOpcodeCount || eq_op >= it->EQOpcodeCount)
return;
it->emu_to_eq[emu_op] = eq_op;
it->eq_to_emu[eq_op] = emu_op;
}
NullOpcodeManager::NullOpcodeManager()
: MutableOpcodeManager() {
}
bool NullOpcodeManager::LoadOpcodes(map<string, uint16>* eq) {
return(true);
}
bool NullOpcodeManager::LoadOpcodes(const char *filename) {
return(true);
}
bool NullOpcodeManager::ReloadOpcodes(const char *filename) {
return(true);
}
uint16 NullOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
return(0);
}
EmuOpcode NullOpcodeManager::EQToEmu(const uint16 eq_op) {
return(OP_Unknown);
}
EmptyOpcodeManager::EmptyOpcodeManager()
: MutableOpcodeManager() {
}
bool EmptyOpcodeManager::LoadOpcodes(const char *filename) {
return(true);
}
bool EmptyOpcodeManager::LoadOpcodes(map<string, uint16>* eq) {
return(true);
}
bool EmptyOpcodeManager::ReloadOpcodes(const char *filename) {
return(true);
}
uint16 EmptyOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
map<EmuOpcode, uint16>::iterator f;
f = emu_to_eq.find(emu_op);
return(f == emu_to_eq.end()? 0 : f->second);
}
EmuOpcode EmptyOpcodeManager::EQToEmu(const uint16 eq_op) {
map<uint16, EmuOpcode>::iterator f;
f = eq_to_emu.find(eq_op);
return(f == eq_to_emu.end()?OP_Unknown:f->second);
}
void EmptyOpcodeManager::SetOpcode(EmuOpcode emu_op, uint16 eq_op) {
emu_to_eq[emu_op] = eq_op;
eq_to_emu[eq_op] = emu_op;
}