Browse Source

Various bug fixes, added checks to ensure we wont send bad packets to client if the opcode for the client doesnt exit

LethalEncounter 3 years ago
parent
commit
74bd3c5a52

+ 29 - 11
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -9133,14 +9133,11 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 			}
 		}
 		else if (atoi(sep->arg[0]) == 24) {
-			PacketStruct* packet2 = configReader.getStruct("WS_TintWidgetsMsg", client->GetVersion());
+			PacketStruct* packet2 = configReader.getStruct("WS_EnableGameEvent", client->GetVersion());
 			if (packet2) {
-				if (sep->IsSet(4)) {
-					int32 id = atoul(sep->arg[1]);
-					packet2->setDataByName("object_id", id);
-					packet2->setDataByName("tint_red", atoi(sep->arg[2]));
-					packet2->setDataByName("tint_green", atoi(sep->arg[3]));
-					packet2->setDataByName("tint_blue", atoi(sep->arg[4]));
+				if (sep->IsSet(2)) {
+					packet2->setDataByName("event_name", sep->arg[1]);
+					packet2->setDataByName("enabled", atoi(sep->arg[2]));					
 					EQ2Packet* app = packet2->serialize();
 					DumpPacket(app);
 					client->QueuePacket(app);
@@ -9192,10 +9189,11 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 				packet2->setSubstructDataByName("header", "defender", client->GetPlayer()->GetIDWithPlayerSpawn(target));
 				packet2->setSubstructDataByName("header", "defender_proxy", client->GetPlayer()->GetIDWithPlayerSpawn(target));
 				packet2->setSubstructDataByName("header", "attacker", client->GetPlayer()->GetIDWithPlayerSpawn(client->GetPlayer()));
-				packet2->setSubstructDataByName("header", "normal_hit", 1);
-				packet2->setDataByName("damage_type", atoi(sep->arg[1]));
-				packet2->setDataByName("damage", atoi(sep->arg[2]));
-
+				packet2->setArrayLengthByName("num_dmg", 1);				
+				packet2->setArrayDataByName("damage_type", atoi(sep->arg[1]));
+				packet2->setArrayDataByName("damage", atoi(sep->arg[2]));
+				packet2->setDataByName("spell", 1);
+				packet2->setDataByName("spell_name", "Testing");
 				EQ2Packet* app = packet2->serialize();
 				if (sep->IsSet(4)) {
 					int16 offset = atoi(sep->arg[3]);
@@ -9217,6 +9215,26 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 						memcpy(ptr2, sep->arg[4], len);
 					}
 				}
+				if (sep->IsSet(6)) {
+					int16 offset = atoi(sep->arg[5]);
+					uchar* ptr2 = app->pBuffer;
+					ptr2 += offset;
+					if (sep->IsNumber(6)) {
+						int32 value1 = atol(sep->arg[6]);
+						if (value1 > 0xFFFF)
+							memcpy(ptr2, (uchar*)&value1, 4);
+						else if (value1 > 0xFF)
+							memcpy(ptr2, (uchar*)&value1, 2);
+						else
+							memcpy(ptr2, (uchar*)&value1, 1);
+					}
+					else {
+						int8 len = strlen(sep->arg[6]);
+						memcpy(ptr2, (uchar*)&len, 1);
+						ptr2 += 1;
+						memcpy(ptr2, sep->arg[6], len);
+					}
+				}
 				DumpPacket(app);
 				client->QueuePacket(app);
 				safe_delete(packet2);

+ 2 - 1
EQ2/source/WorldServer/Guilds/Guild.cpp

@@ -703,7 +703,8 @@ bool Guild::AddNewGuildMember(Client *client, const char *invited_by, int8 rank)
 		SendGuildBankEventList(client);
 		SendAllGuildEvents(client);
 		SendGuildMemberList(client);
-		client->GetCurrentZone()->SendUpdateTitles(client->GetPlayer());
+		if(client->GetVersion() > 546)
+			client->GetCurrentZone()->SendUpdateTitles(client->GetPlayer());
 
 		if (invited_by) {
 			AddNewGuildEvent(GUILD_EVENT_MEMBER_JOINS, "%s has accepted %s's invitation to join %s.", Timer::GetUnixTimeStamp(), true, player->GetName(), invited_by, GetName());

+ 29 - 0
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -9563,6 +9563,35 @@ int EQ2Emu_lua_ShowWindow(lua_State* state) {
 	return 0;
 }
 
+int EQ2Emu_lua_EnableGameEvent(lua_State* state) {
+	//See GameEvents.txt for options that can be used for this function
+	if (!lua_interface)
+		return 0;
+	Client* client = 0;
+	Spawn* player = lua_interface->GetSpawn(state);
+	string event_name = lua_interface->GetStringValue(state, 2);
+	int8 enabled = lua_interface->GetInt8Value(state, 3);
+	if (!player || !player->IsPlayer()) {
+		lua_interface->LogError("LUA EnableGameEvent error: player is not valid");
+		return 0;
+	}
+	if (player->GetZone())
+		client = player->GetZone()->GetClientBySpawn(player);
+
+	if (!client) {
+		lua_interface->LogError("LUA EnableGameEvent error: could not find client");
+		return 0;
+	}
+	PacketStruct* packet = configReader.getStruct("WS_EnableGameEvent", client->GetVersion());
+	if (packet) {
+		packet->setDataByName("event_name", event_name.c_str());
+		packet->setDataByName("enabled", enabled);
+		client->QueuePacket(packet->serialize());
+		safe_delete(packet);
+	}
+	return 0;
+}
+
 int EQ2Emu_lua_FlashWindow(lua_State* state) {
 	if (!lua_interface)
 		return 0;

+ 1 - 0
EQ2/source/WorldServer/LuaFunctions.h

@@ -424,6 +424,7 @@ int EQ2Emu_lua_AddPrimaryEntityCommandAllSpawns(lua_State* state);
 int EQ2Emu_lua_InstructionWindow(lua_State* state);
 int EQ2Emu_lua_ShowWindow(lua_State* state);
 int EQ2Emu_lua_FlashWindow(lua_State* state);
+int EQ2Emu_lua_EnableGameEvent(lua_State* state);
 
 int EQ2Emu_lua_CheckLOS(lua_State* state);
 int EQ2Emu_lua_CheckLOSByCoordinates(lua_State* state);

+ 1 - 0
EQ2/source/WorldServer/LuaInterface.cpp

@@ -1025,6 +1025,7 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
 	lua_register(state, "InstructionWindow", EQ2Emu_lua_InstructionWindow);
 	lua_register(state, "ShowWindow", EQ2Emu_lua_ShowWindow);
 	lua_register(state, "FlashWindow", EQ2Emu_lua_FlashWindow);
+	lua_register(state, "EnableGameEvent", EQ2Emu_lua_EnableGameEvent);
 	lua_register(state, "DisplayText", EQ2Emu_lua_DisplayText);
 
 	lua_register(state, "CheckLOS", EQ2Emu_lua_CheckLOS);

+ 0 - 2
EQ2/source/WorldServer/Spawn.cpp

@@ -3476,8 +3476,6 @@ void Spawn::CopySpawnAppearance(Spawn* spawn){
 
 void Spawn::SetY(float y, bool updateFlags, bool disableYMapCheck)
 {
-	if (IsPlayer())
-		cout << "sdfsd\n";
 	SetPos(&appearance.pos.Y, y, updateFlags);
 	if (!disableYMapCheck)
 		FixZ();

+ 10 - 8
EQ2/source/WorldServer/zoneserver.cpp

@@ -4527,7 +4527,7 @@ void ZoneServer::SendDamagePacket(Spawn* attacker, Spawn* victim, int8 type1, in
 			packet = configReader.getStruct("WS_HearSiphonSpellDamage", client->GetVersion());
 			break;
 		case DAMAGE_PACKET_TYPE_MULTIPLE_DAMAGE:
-			if (client->GetVersion() > 283)
+			if (client->GetVersion() > 546)
 				packet = configReader.getStruct("WS_HearMultipleDamage", client->GetVersion());
 			else
 				packet = configReader.getStruct("WS_HearSimpleDamage", client->GetVersion());
@@ -4540,7 +4540,7 @@ void ZoneServer::SendDamagePacket(Spawn* attacker, Spawn* victim, int8 type1, in
 		case DAMAGE_PACKET_TYPE_SPELL_DAMAGE3:
 		case DAMAGE_PACKET_TYPE_SPELL_CRIT_DMG:
 		case DAMAGE_PACKET_TYPE_SPELL_DAMAGE:
-			if (client->GetVersion() > 283)
+			if (client->GetVersion() > 546)
 				packet = configReader.getStruct("WS_HearSpellDamage", client->GetVersion());
 			else
 				packet = configReader.getStruct("WS_HearSimpleDamage", client->GetVersion());
@@ -4561,9 +4561,11 @@ void ZoneServer::SendDamagePacket(Spawn* attacker, Spawn* victim, int8 type1, in
 		}
 
 		if (packet) {
-			if (client->GetVersion() >= 284) {
+			if (client->GetVersion() > 546) {
 				packet->setSubstructDataByName("header", "packet_type", type1);
 				packet->setSubstructDataByName("header", "result_type", type2);
+				packet->setDataByName("damage_type", damage_type);
+				packet->setDataByName("damage", damage);
 			}
 			else {
 				switch (type2) {
@@ -4595,16 +4597,16 @@ void ZoneServer::SendDamagePacket(Spawn* attacker, Spawn* victim, int8 type1, in
 					packet->setSubstructDataByName("header", "result_type", 11);
 					break;
 				}
-				packet->setSubstructDataByName("header", "normal_hit", 1);
+				packet->setArrayLengthByName("num_dmg", 1);
 				packet->setSubstructDataByName("header", "defender_proxy", client->GetPlayer()->GetIDWithPlayerSpawn(victim));
+				packet->setArrayDataByName("damage_type", damage_type);
+				packet->setArrayDataByName("damage", damage);
 			}
 			if (!attacker)
 				packet->setSubstructDataByName("header", "attacker", 0xFFFFFFFF);
 			else
 				packet->setSubstructDataByName("header", "attacker", client->GetPlayer()->GetIDWithPlayerSpawn(attacker));
-			packet->setSubstructDataByName("header", "defender", client->GetPlayer()->GetIDWithPlayerSpawn(victim));
-			packet->setDataByName("damage_type", damage_type);
-			packet->setDataByName("damage", damage);
+			packet->setSubstructDataByName("header", "defender", client->GetPlayer()->GetIDWithPlayerSpawn(victim));			
 			if (spell_name) {
 				packet->setDataByName("spell", 1);
 				packet->setDataByName("spell_name", spell_name);
@@ -6057,7 +6059,7 @@ void ZoneServer::SendUpdateTitles(Spawn *spawn, Title *suffix, Title *prefix) {
 		current_client = *itr;
 
 		if (!(packet = configReader.getStruct("WS_UpdateTitle", current_client->GetVersion())))
-			break;
+			continue;
 
 		packet->setDataByName("player_id", current_client->GetPlayer()->GetIDWithPlayerSpawn(spawn));
 		packet->setDataByName("player_name", spawn->GetName());

+ 5 - 6
EQ2/source/common/ConfigReader.cpp

@@ -78,17 +78,16 @@ PacketStruct* ConfigReader::getStruct(const char* name, int16 version){
 				latest_version = *iter;
 		}		
 		if (latest_version) {
-			if(strlen(latest_version->GetOpcodeType()) == 0 || latest_version->GetOpcode() != OP_Unknown)
-				new_latest_version = new PacketStruct(latest_version, version);
-			else {
-				cout << "here: " << latest_version->GetOpcodeType() << endl;
-				LogWrite(PACKET__ERROR, 0, "Packet", "Could not find valid opcode for Packet Struct '%s' and client version %d", latest_version->GetOpcodeType(), version);
+			if (latest_version->GetOpcode() != OP_Unknown && latest_version->GetOpcodeValue(version) == 0xFFFF) {
+				LogWrite(PACKET__ERROR, 0, "Packet", "Could not find valid opcode for Packet Struct '%s' and client version %d", latest_version->GetName(), version);
 			}
+			else if(strlen(latest_version->GetOpcodeType()) == 0 || latest_version->GetOpcode() != OP_Unknown)
+				new_latest_version = new PacketStruct(latest_version, version);
 		}
 			
 	}
 	MStructs.unlock();
-	if(!new_latest_version)
+	if(!new_latest_version && !latest_version)
 		LogWrite(PACKET__ERROR, 0, "Packet", "Could not find struct named '%s'", name);
 	return new_latest_version;
 }

+ 29 - 12
EQ2/source/common/PacketStruct.cpp

@@ -1553,6 +1553,34 @@ int32 PacketStruct::GetArraySizeByName(const char* name, int32 index) {
 	return GetArraySize(ds1, index);
 }
 
+int16 PacketStruct::GetOpcodeValue(int16 client_version) {
+	int16 opcode = 0xFFFF;
+	bool client_cmd = false;
+#ifndef LOGIN
+	if (GetOpcode() == OP_ClientCmdMsg && strlen(GetOpcodeType()) > 0 && !IsSubPacket())
+		client_cmd = true;
+#endif
+	if (client_cmd) {
+		EmuOpcode sub_opcode = EQOpcodeManager[0]->NameSearch(GetOpcodeType());
+		int16 opcode_val = 0;
+		if (sub_opcode != OP_Unknown) { //numbers should be used at OpcodeTypes, define them!
+			int16 OpcodeVersion = GetOpcodeVersion(client_version);
+			if(EQOpcodeManager.count(OpcodeVersion) > 0)
+				opcode = EQOpcodeManager[OpcodeVersion]->EmuToEQ(sub_opcode);
+		}		
+	}
+	else {
+		int16 OpcodeVersion = GetOpcodeVersion(client_version);
+		if (EQOpcodeManager.count(OpcodeVersion) > 0)
+			opcode = EQOpcodeManager[OpcodeVersion]->EmuToEQ(GetOpcode());
+	}
+#ifndef LOGIN
+	if(opcode == 0)
+		opcode = 0xFFFF;
+#endif
+	return opcode;
+}
+
 void PacketStruct::serializePacket(bool clear) {
 	if (clear)
 		Clear();
@@ -1717,22 +1745,11 @@ void PacketStruct::serializePacket(bool clear) {
 	}
 #ifndef LOGIN
 	if (client_cmd) {
-		EmuOpcode sub_opcode = EQOpcodeManager[0]->NameSearch(GetOpcodeType());
-		int16 opcode_val = 0;
-		if (sub_opcode == OP_Unknown) {
-			try {
-				opcode_val = atoi(GetOpcodeType());
-			}
-			catch (...) {}
-		}
+		int16 opcode_val = GetOpcodeValue(client_version);		
 		Clear();
 		int32 size = client_data.length() + 3; //gotta add the opcode and oversized
 		int8 oversized = 0xFF;
 		int16 OpcodeVersion = GetOpcodeVersion(client_version);
-		if (opcode_val == 0)
-			opcode_val = EQOpcodeManager[OpcodeVersion]->EmuToEQ(sub_opcode);
-		if (opcode_val == 0)
-			LogWrite(PACKET__ERROR, 0, "Packet", "PACKET NOT SENT CORRECTLY!  Unable to get Emu Opcode from: '%s'", GetOpcodeType());
 		if (opcode_val == EQOpcodeManager[OpcodeVersion]->EmuToEQ(OP_EqExamineInfoCmd) && client_version > 546)
 			size += (size - 9);
 		if (client_version <= 283) {

+ 1 - 0
EQ2/source/common/PacketStruct.h

@@ -462,6 +462,7 @@ public:
 	void SetVersion(int32 in_version) { version = in_version; }
 	bool SetOpcode(const char* new_opcode);
 	EmuOpcode GetOpcode() { return opcode; }
+	int16 GetOpcodeValue(int16 client_version);
 	const char* GetName() { return name.c_str(); }
 	void SetName(const char* in_name) { name = string(in_name); }
 	bool LoadedSuccessfully() { return loadedSuccessfully; }

+ 1 - 0
EQ2/source/common/opcodemgr.cpp

@@ -60,6 +60,7 @@ bool OpcodeManager::LoadOpcodesMap(map<string, uint16>* eq, OpcodeSetStrategy *s
 		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, 0);
 			continue;	//continue to give them a list of all missing opcodes
 		}
 		

+ 21 - 7
server/WorldStructs.xml

@@ -328,6 +328,10 @@ to zero and treated like placeholders." />
 <Data ElementName="window" Type="EQ2_16Bit_String" />
 <Data ElementName="show" Type="int8" Size="1" />
 </Struct>
+<Struct Name="WS_EnableGameEvent" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqEnableGameEventCmd">
+<Data ElementName="event_name" Type="EQ2_16Bit_String" />
+<Data ElementName="enabled" Type="int8" Size="1" />
+</Struct>
 <Struct Name="WS_FlashWindow" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqFlashWindowCmd">
 <Data ElementName="window" Type="EQ2_16Bit_String" />
 <Data ElementName="flash_seconds" Type="float" Size="1" />
@@ -2797,8 +2801,6 @@ to zero and treated like placeholders." />
 <Data ElementName="defender_proxy" Type="int32" />
 <Data ElementName="result_type" Type="int8" />
 <Data ElementName="combat_chat_method" Type="int32" /> <!-- should probably always be 0 -->
-<Data ElementName="normal_hit" Type="int16" /> <!-- if this is 0, then client shows melee attack upon successful spell -->
-<Data ElementName="unknown1" Type="int32" />
 </Struct>
 <Struct Name="WS_HearDamage_Header" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqHearCombatCmd">
 <Data ElementName="attacker" Type="int32" />
@@ -2806,7 +2808,6 @@ to zero and treated like placeholders." />
 <Data ElementName="defender_proxy" Type="int32" />
 <Data ElementName="result_type" Type="int8" />
 <Data ElementName="combat_chat_method" Type="int32" /> <!-- should probably always be 0 -->
-<Data ElementName="normal_hit" Type="int16" /> <!-- if this is 0, then client shows melee attack upon successful spell -->
 </Struct>
 <Struct Name="WS_HearDamage_Header" ClientVersion="547" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqHearCombatCmd">
 <Data ElementName="packet_type" Type="int8" />
@@ -2824,15 +2825,28 @@ to zero and treated like placeholders." />
 </Struct>
 <Struct Name="WS_HearSimpleDamage" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqHearCombatCmd">
 <Data ElementName="header" Substruct="WS_HearDamage_Header" Size="1" />
-<Data ElementName="damage" Type="int32" />
-<Data ElementName="damage_type" Type="int8" />
+<Data ElementName="num_dmg" Type="int8" />
+<Data ElementName="siphon_type" Type="int8" />
+<Data ElementName="unknown1" Type="int32" />
+<Data ElementName="dmg_array" Type="Array" ArraySizeVariable="num_dmg">
+	<Data ElementName="damage" Type="int32" />
+	<Data ElementName="damage_type" Type="int8" />
+</Data>
 <Data ElementName="spell" Type="int8" />
 <Data ElementName="spell_name" Type="EQ2_16Bit_String" Size="1" />
 </Struct>
 <Struct Name="WS_HearSimpleDamage" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqHearCombatCmd">
 <Data ElementName="header" Substruct="WS_HearDamage_Header" Size="1" />
-<Data ElementName="damage_type" Type="int8" />
-<Data ElementName="damage" Type="int16" />
+<Data ElementName="num_dmg" Type="int8" />
+<Data ElementName="siphon_type" Type="int8" />
+<Data ElementName="dmg_array" Type="Array" ArraySizeVariable="num_dmg">
+	<Data ElementName="damage_type" Type="int8" />
+	<Data ElementName="damage" Type="int16" />
+	<Data ElementName="unknown1" Type="int8" />
+	<Data ElementName="unknown2" Type="int8" />
+	<Data ElementName="crit_flag" Type="int8" /> <!-- 4==crit -->
+	<Data ElementName="unknown4" Type="int8" />
+</Data>
 <Data ElementName="spell" Type="int8" />
 <Data ElementName="spell_name" Type="EQ2_16Bit_String" Size="1" />
 </Struct>