001/*
002 * Forge Mod Loader
003 * Copyright (c) 2012-2013 cpw.
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser Public License v2.1
006 * which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
008 * 
009 * Contributors:
010 *     cpw - implementation
011 */
012
013package cpw.mods.fml.client.modloader;
014
015import java.util.Collection;
016import java.util.Collections;
017import java.util.Map;
018import java.util.Map.Entry;
019import java.util.logging.Level;
020
021import net.minecraft.client.Minecraft;
022import net.minecraft.network.INetworkManager;
023import net.minecraft.network.packet.NetHandler;
024import net.minecraft.network.packet.Packet250CustomPayload;
025import net.minecraft.src.BaseMod;
026import net.minecraft.client.*;
027import net.minecraft.client.entity.EntityClientPlayerMP;
028import net.minecraft.client.multiplayer.NetClientHandler;
029import net.minecraft.client.renderer.entity.Render;
030import net.minecraft.client.renderer.entity.RenderManager;
031import net.minecraft.client.settings.KeyBinding;
032import net.minecraft.entity.Entity;
033import net.minecraft.entity.player.EntityPlayer;
034
035import com.google.common.base.Equivalence;
036import com.google.common.base.Supplier;
037import com.google.common.base.Suppliers;
038import com.google.common.collect.Iterables;
039import com.google.common.collect.Iterators;
040import com.google.common.collect.MapDifference;
041import com.google.common.collect.MapDifference.ValueDifference;
042import com.google.common.collect.MapMaker;
043import com.google.common.collect.Maps;
044import com.google.common.collect.Multimap;
045import com.google.common.collect.Multimaps;
046
047import cpw.mods.fml.client.FMLClientHandler;
048import cpw.mods.fml.client.registry.KeyBindingRegistry;
049import cpw.mods.fml.client.registry.RenderingRegistry;
050import cpw.mods.fml.common.FMLLog;
051import cpw.mods.fml.common.Loader;
052import cpw.mods.fml.common.modloader.BaseModProxy;
053import cpw.mods.fml.common.modloader.IModLoaderSidedHelper;
054import cpw.mods.fml.common.modloader.ModLoaderHelper;
055import cpw.mods.fml.common.modloader.ModLoaderModContainer;
056import cpw.mods.fml.common.network.EntitySpawnPacket;
057import cpw.mods.fml.common.registry.EntityRegistry.EntityRegistration;
058
059public class ModLoaderClientHelper implements IModLoaderSidedHelper
060{
061    public static int obtainBlockModelIdFor(BaseMod mod, boolean inventoryRenderer)
062    {
063        int renderId=RenderingRegistry.getNextAvailableRenderId();
064        ModLoaderBlockRendererHandler bri=new ModLoaderBlockRendererHandler(renderId, inventoryRenderer, mod);
065        RenderingRegistry.registerBlockHandler(bri);
066        return renderId;
067    }
068
069
070    public static void handleFinishLoadingFor(ModLoaderModContainer mc, Minecraft game)
071    {
072        FMLLog.log(mc.getModId(), Level.FINE, "Handling post startup activities for ModLoader mod %s", mc.getModId());
073        BaseMod mod = (BaseMod) mc.getMod();
074
075        Map<Class<? extends Entity>, Render> renderers = Maps.newHashMap(RenderManager.instance.entityRenderMap);
076
077        try
078        {
079            FMLLog.log(mc.getModId(), Level.FINEST, "Requesting renderers from basemod %s", mc.getModId());
080            mod.addRenderer(renderers);
081            FMLLog.log(mc.getModId(), Level.FINEST, "Received %d renderers from basemod %s", renderers.size(), mc.getModId());
082        }
083        catch (Exception e)
084        {
085            FMLLog.log(mc.getModId(), Level.SEVERE, e, "A severe problem was detected with the mod %s during the addRenderer call. Continuing, but expect odd results", mc.getModId());
086        }
087
088        MapDifference<Class<? extends Entity>, Render> difference = Maps.difference(RenderManager.instance.entityRenderMap, renderers, Equivalence.identity());
089
090        for ( Entry<Class<? extends Entity>, Render> e : difference.entriesOnlyOnLeft().entrySet())
091        {
092            FMLLog.log(mc.getModId(), Level.WARNING, "The mod %s attempted to remove an entity renderer %s from the entity map. This will be ignored.", mc.getModId(), e.getKey().getName());
093        }
094
095        for (Entry<Class<? extends Entity>, Render> e : difference.entriesOnlyOnRight().entrySet())
096        {
097            FMLLog.log(mc.getModId(), Level.FINEST, "Registering ModLoader entity renderer %s as instance of %s", e.getKey().getName(), e.getValue().getClass().getName());
098            RenderingRegistry.registerEntityRenderingHandler(e.getKey(), e.getValue());
099        }
100
101        for (Entry<Class<? extends Entity>, ValueDifference<Render>> e : difference.entriesDiffering().entrySet())
102        {
103            FMLLog.log(mc.getModId(), Level.FINEST, "Registering ModLoader entity rendering override for %s as instance of %s", e.getKey().getName(), e.getValue().rightValue().getClass().getName());
104            RenderingRegistry.registerEntityRenderingHandler(e.getKey(), e.getValue().rightValue());
105        }
106
107        try
108        {
109            mod.registerAnimation(game);
110        }
111        catch (Exception e)
112        {
113            FMLLog.log(mc.getModId(), Level.SEVERE, e, "A severe problem was detected with the mod %s during the registerAnimation call. Continuing, but expect odd results", mc.getModId());
114        }
115    }
116
117    public ModLoaderClientHelper(Minecraft client)
118    {
119        this.client = client;
120        ModLoaderHelper.sidedHelper = this;
121        keyBindingContainers = Multimaps.newMultimap(Maps.<ModLoaderModContainer, Collection<ModLoaderKeyBindingHandler>>newHashMap(), new Supplier<Collection<ModLoaderKeyBindingHandler>>()
122        {
123            @Override
124            public Collection<ModLoaderKeyBindingHandler> get()
125            {
126                return Collections.singleton(new ModLoaderKeyBindingHandler());
127            }
128        });
129    }
130
131    private Minecraft client;
132    private static Multimap<ModLoaderModContainer, ModLoaderKeyBindingHandler> keyBindingContainers;
133
134    @Override
135    public void finishModLoading(ModLoaderModContainer mc)
136    {
137        handleFinishLoadingFor(mc, client);
138    }
139
140
141    public static void registerKeyBinding(BaseModProxy mod, KeyBinding keyHandler, boolean allowRepeat)
142    {
143        ModLoaderModContainer mlmc = (ModLoaderModContainer) Loader.instance().activeModContainer();
144        ModLoaderKeyBindingHandler handler = Iterables.getOnlyElement(keyBindingContainers.get(mlmc));
145        handler.setModContainer(mlmc);
146        handler.addKeyBinding(keyHandler, allowRepeat);
147        KeyBindingRegistry.registerKeyBinding(handler);
148    }
149
150
151    @Override
152    public Object getClientGui(BaseModProxy mod, EntityPlayer player, int ID, int x, int y, int z)
153    {
154        return ((net.minecraft.src.BaseMod)mod).getContainerGUI((EntityClientPlayerMP) player, ID, x, y, z);
155    }
156
157
158    @Override
159    public Entity spawnEntity(BaseModProxy mod, EntitySpawnPacket input, EntityRegistration er)
160    {
161        return ((net.minecraft.src.BaseMod)mod).spawnEntity(er.getModEntityId(), client.theWorld, input.scaledX, input.scaledY, input.scaledZ);
162    }
163
164
165    @Override
166    public void sendClientPacket(BaseModProxy mod, Packet250CustomPayload packet)
167    {
168        ((net.minecraft.src.BaseMod)mod).clientCustomPayload(client.thePlayer.sendQueue, packet);
169    }
170
171    private Map<INetworkManager,NetHandler> managerLookups = new MapMaker().weakKeys().weakValues().makeMap();
172    @Override
173    public void clientConnectionOpened(NetHandler netClientHandler, INetworkManager manager, BaseModProxy mod)
174    {
175        managerLookups.put(manager, netClientHandler);
176        ((BaseMod)mod).clientConnect((NetClientHandler)netClientHandler);
177    }
178
179
180    @Override
181    public boolean clientConnectionClosed(INetworkManager manager, BaseModProxy mod)
182    {
183        if (managerLookups.containsKey(manager))
184        {
185            ((BaseMod)mod).clientDisconnect((NetClientHandler) managerLookups.get(manager));
186            return true;
187        }
188        return false;
189    }
190}