package de.lighti.packet;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.logging.Logger;
import com.valve.dota2.Demo.CDemoSendTables;
import com.valve.dota2.Netmessages.CSVCMsg_CreateStringTable;
import com.valve.dota2.Netmessages.CSVCMsg_GameEventList;
import com.valve.dota2.Netmessages.CSVCMsg_PacketEntities;
import com.valve.dota2.Netmessages.CSVCMsg_SendTable;
import com.valve.dota2.Netmessages.CSVCMsg_SendTable.sendprop_t;
import com.valve.dota2.Netmessages.CSVCMsg_ServerInfo;
import com.valve.dota2.Netmessages.CSVCMsg_TempEntities;
import com.valve.dota2.Netmessages.CSVCMsg_UpdateStringTable;
import com.valve.dota2.Netmessages.SVC_Messages;
import com.valve.dota2.Networkbasetypes.CSVCMsg_GameEvent;
import com.valve.dota2.Networkbasetypes.CSVCMsg_UserMessage;
import de.lighti.DotaPlay;
import de.lighti.model.state.ParseState;
import de.lighti.model.state.StateUtils;
import de.lighti.model.state.StateUtils.ST_Flags;
import de.lighti.model.state.StateUtils.SendProp;
import de.lighti.model.state.StateUtils.SendTable;
import de.lighti.model.state.StateUtils.StringTable;
import de.lighti.model.state.StateUtils.StringTableEntry;
import de.lighti.util.BitInputBuffer;
import de.lighti.util.Utils;
public class SVCMessageHandler {
private static void handleCreateTable( CSVCMsg_CreateStringTable table, ParseState state ) {
if (state == null) {
throw new IllegalStateException( "SVC_CreateStringTable but no state." );
}
final StringTable converted = state.createStringTable( table.getName(), table.getMaxEntries(), table.getFlags(), table.getUserDataFixedSize(),
table.getUserDataSize(), table.getUserDataSizeBits() );
if (table.getName().equals( INSTANCE_BASELINE_TABLE )) {
updateStringTable( converted, table.getNumEntries(), table.getStringData().asReadOnlyByteBuffer() );
}
else {
Logger.getLogger( SVCMessageHandler.class.getName() ).fine( "Table " + table.getName() + " is not implemented." );
}
}
private static void handleGameEventList( CSVCMsg_GameEventList e ) {
DotaPlay.getState().setGameEventList( e );
}
private static void handleSendTable( CSVCMsg_SendTable table, ParseState state ) {
if (state == null) {
throw new IllegalStateException( "SVC_SendTable but no state created." );
}
final SendTable converted = state.createSendTable( table.getNetTableName(), table.getNeedsDecoder() );
for (final sendprop_t prop : table.getPropsList()) {
Logger.getLogger( DotaPlay.class.getName() ).finest( "Property created " + prop.getVarName() );
final SendProp c = new SendProp( StateUtils.SP_Type.valueOf( prop.getType() ), prop.getVarName(), prop.getFlags(), prop.getPriority(),
prop.getDtName(), prop.getNumElements(), prop.getLowValue(), prop.getHighValue(), prop.getNumBits() );
converted.getProps().add( c );
}
}
public static void handleSendTables( CDemoSendTables tables, ParseState state ) throws IOException {
final ByteBuffer data = tables.getData().asReadOnlyByteBuffer();
while (data.hasRemaining()) {
final int command = Utils.readVarInt( data );
final int size = Utils.readVarInt( data );
if (command != SVC_Messages.svc_SendTable.getNumber()) {
throw new IllegalStateException( "Command " + command + " in DEM_SendTables." );
}
final byte[] bytes = new byte[size];
data.get( bytes );
final CSVCMsg_SendTable sendTable = CSVCMsg_SendTable.parseFrom( bytes );
handleSendTable( sendTable, state );
}
}
public static void handleSVCMessage( int cmd, int size, ByteBuffer buffer ) throws IOException {
final SVC_Messages msg = SVC_Messages.valueOf( cmd );
final byte[] bytes = new byte[size];
buffer.get( bytes );
switch (msg) {
case svc_GameEvent: {
final CSVCMsg_GameEvent e = CSVCMsg_GameEvent.parseFrom( bytes );
GameEvent.handleGameEvent( e );
break;
}
case svc_GameEventList: {
final CSVCMsg_GameEventList e = CSVCMsg_GameEventList.parseFrom( bytes );
handleGameEventList( e );
break;
}
case svc_PacketEntities: {
final CSVCMsg_PacketEntities e = CSVCMsg_PacketEntities.parseFrom( bytes );
Entities.handlePacketEntities( e, DotaPlay.getState() );
break;
}
case svc_UserMessage: {
final CSVCMsg_UserMessage e = CSVCMsg_UserMessage.parseFrom( bytes );
UserMessage.handleUserMessage( e );
break;
}
case svc_ServerInfo:
if (DotaPlay.getState() != null) {
throw new IllegalStateException( "We already seen a server info" );
}
final CSVCMsg_ServerInfo si = CSVCMsg_ServerInfo.parseFrom( bytes );
DotaPlay.setState( new ParseState( si.getProtocol(), si.getMaxClasses() ) );
DotaPlay.getState().setTickInterval( si.getTickInterval() );
break;
case svc_CreateStringTable:
final CSVCMsg_CreateStringTable create = CSVCMsg_CreateStringTable.parseFrom( bytes );
handleCreateTable( create, DotaPlay.getState() );
break;
case svc_UpdateStringTable:
final CSVCMsg_UpdateStringTable update = CSVCMsg_UpdateStringTable.parseFrom( bytes );
final StringTable table = DotaPlay.getState().getStringTable( update.getTableId() );
if (table == null) {
throw new IllegalStateException( "Trying to update a non-existing table" );
}
if (table.getName().equals( INSTANCE_BASELINE_TABLE )) {
updateStringTable( table, update.getNumChangedEntries(), update.getStringData().asReadOnlyByteBuffer() );
}
else {
Logger.getLogger( SVCMessageHandler.class.getName() ).fine( "not updating " + table.getName() );
}
break;
case svc_TempEntities:
final CSVCMsg_TempEntities te = CSVCMsg_TempEntities.parseFrom( bytes );
handleTempEntities( te );
break;
case svc_EntityMessage:
case svc_BSPDecal:
case svc_ClassInfo:
case svc_CrosshairAngle:
case svc_FixAngle:
case svc_GetCvarValue:
case svc_Menu:
case svc_Prefetch:
case svc_Print:
case svc_SendTable:
case svc_SetPause:
case svc_SetView:
case svc_Sounds:
case svc_SplitScreen:
case svc_VoiceData:
case svc_VoiceInit:
default:
// System.out.println( msg.name() );
break;
}
}
private static void handleTempEntities( CSVCMsg_TempEntities te ) {
// System.out.println( "TempEntities with " + te.getNumEntries() + " entries" );
final BitInputBuffer buffer = new BitInputBuffer( te.getEntityData().asReadOnlyByteBuffer() );
// System.out.println( buffer );
}
private static void updateStringTable( StringTable table, int numEntries, ByteBuffer stringData ) {
final BitInputBuffer stream = new BitInputBuffer( stringData );
Logger.getLogger( SVCMessageHandler.class.getName() ).finer( "Update package has " + stringData.capacity() + " bytes" );
Logger.getLogger( SVCMessageHandler.class.getName() ).finer( "Expecting " + numEntries + " entires" );
final boolean first = stream.readBit();
int entryId = -1;
int entriesRead = 0;
final int oldSize = table.size();
while (entriesRead < numEntries) {
if (!stream.readBit()) {
entryId = stream.readBitsAsInt( table.getEntryBits() );
}
else {
entryId += 1;
}
if (entryId >= table.getMaxEntries()) {
throw new IllegalStateException( "Entry id too large" );
}
String key = null;
if (stream.readBit()) {
if (first && stream.readBit()) {
throw new UnsupportedOperationException( "please no" );
}
else {
if (stream.readBit()) {
throw new UnsupportedOperationException( "no substring" );
}
else {
key = stream.readString( MAX_KEY_SIZE );
}
}
}
byte[] valueBuffer = null;
int length = 0;
if (stream.readBit()) {
if ((table.getFlags() & ST_Flags.ST_FixedLength.getId()) > 0) {
length = table.getUserDataSize();
}
else {
length = stream.readBitsAsInt( 14 );
}
if (length >= MAX_VALUE_SIZE) {
throw new IllegalStateException( "Message too long." );
}
valueBuffer = new byte[length];
for (int i = 0; i < length; i++) {
valueBuffer[i] = (byte) stream.readBitsAsInt( 8 );
}
}
if (entryId < table.size()) {
final StringTableEntry item = table.get( entryId );
if (key != null && !item.key.equals( key )) {
throw new IllegalStateException( "Entry's keys don't match." );
}
item.value = valueBuffer;
}
else {
if (key == null) {
throw new IllegalStateException( "Creating a new string table entry but no key specified." );
}
table.put( new String( key ), valueBuffer );//new String( value_buffer, 0, length ) );
}
++entriesRead;
}
Logger.getLogger( SVCMessageHandler.class.getName() ).finer(
"StringTable " + table.getName() + " updated with " + numEntries + " updated enties. (" + oldSize + "->" + table.size() + ")" );
}
private final static String INSTANCE_BASELINE_TABLE = "instancebaseline";
private final static int MAX_KEY_SIZE = 0x400;
private final static int MAX_VALUE_SIZE = 0x4000;
}