package propra2012.gruppe33.bomberman; import java.awt.Color; import java.awt.Font; import java.awt.Point; import java.awt.Transparency; import java.awt.event.KeyEvent; import java.io.File; import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Random; import java.util.UUID; import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.GridLoader; import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.input.InputActivator; import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.items.CollectableItem; import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.items.spawners.SpawnDead; import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.transform.DeltaPositionBroadcaster; import com.indyforge.foxnet.rmi.InvokerManager; import com.indyforge.foxnet.rmi.pattern.change.AdminSessionServer; import com.indyforge.foxnet.rmi.pattern.change.Session; import com.indyforge.foxnet.rmi.util.Future; import com.indyforge.foxnet.rmi.util.FutureCallback; import com.indyforge.twod.engine.graphics.ImageDesc; import com.indyforge.twod.engine.graphics.rendering.scenegraph.GraphicsEntity; import com.indyforge.twod.engine.graphics.rendering.scenegraph.RenderedImage; import com.indyforge.twod.engine.graphics.rendering.scenegraph.Scene; import com.indyforge.twod.engine.graphics.rendering.scenegraph.SceneProcessor; import com.indyforge.twod.engine.graphics.rendering.scenegraph.Text; import com.indyforge.twod.engine.graphics.rendering.scenegraph.Text.Alignment; import com.indyforge.twod.engine.graphics.rendering.scenegraph.math.Grid; import com.indyforge.twod.engine.graphics.rendering.scenegraph.math.Vector2f; import com.indyforge.twod.engine.graphics.rendering.scenegraph.network.scene.ResetNetworkTimeChange; import com.indyforge.twod.engine.graphics.rendering.scenegraph.network.scene.SceneChange; import com.indyforge.twod.engine.graphics.sprite.Sprite; import com.indyforge.twod.engine.resources.Resource; import com.indyforge.twod.engine.resources.TransientSystemFontResource; import com.indyforge.twod.engine.resources.assets.AssetManager; /** * * @author Christopher Probst * */ public final class Game implements GameConstants, Serializable { /** * */ private static final long serialVersionUID = 1L; public enum Char { Dwarf, Santa, Knight, Wizard } /* * */ private String assetBundle = "res/default.zip", mapPropAssetPath = "assets/maps/map_1.prop"; private float broadcastUpdateTime = 0.001f; private int players = 1; public int players() { return players; } public Game players(int players) { if (players < 1) { throw new IllegalArgumentException("players must be >= 1"); } this.players = players; return this; } public String assetBundle() { return assetBundle; } public Game assetBundle(String assetBundle) { this.assetBundle = assetBundle; return this; } public String mapPropAssetPath() { return mapPropAssetPath; } public Game mapPropAssetPath(String mapPropAssetPath) { this.mapPropAssetPath = mapPropAssetPath; return this; } /** * @return the broadcastUpdateTime */ public float broadcastUpdateTime() { return broadcastUpdateTime; } /** * @param broadcastUpdateTime * the broadcastUpdateTime to set * @return this for chaining. */ public Game boadcastUpdateTime(float broadcastUpdateTime) { this.broadcastUpdateTime = broadcastUpdateTime; return this; } public SceneProcessor serverGame(SceneProcessor sceneProcessor) throws Exception { if (sceneProcessor == null) { throw new NullPointerException("sceneProcessor"); } return serverGame(sceneProcessor, assetBundle, mapPropAssetPath, broadcastUpdateTime, players); } public SceneProcessor serverGame(SceneProcessor sceneProcessor, String assetBundle, String mapPropAssetPath, float broadcastUpdateTime, int players) throws Exception { if (sceneProcessor == null) { throw new NullPointerException("sceneProcessor"); } // Check network mode if (!sceneProcessor.hasAdminSessionServer()) { throw new IllegalArgumentException("The scene processor " + "must a server"); } // Get the server interface final AdminSessionServer<SceneProcessor> server = sceneProcessor .adminSessionServer(); // Here we put the choosen chars Map<Long, Char> charMap = new HashMap<Long, Char>(); // Char random Random r = new Random(); // Session Map<Long, Session<SceneProcessor>> sessions = server.sessionMap(); // Copy ids with chars for (long id : sessions.keySet()) { charMap.put(id, Char.values()[r.nextInt(Char.values().length)]); } /* * SHUTDOWN!!! ??? */ if (players != charMap.size()) { return sceneProcessor.shutdownRequest(true); } // The player refs will be stored here List<UUID> refs = new LinkedList<UUID>(); /* * Create a new server game scene! */ Scene scene = serverGameScene(refs, broadcastUpdateTime, assetBundle, mapPropAssetPath, charMap); // Apply the scene change server.composite().applyChange(new SceneChange(scene)); // Enable input on all clients !! int ptr = 0; for (Long id : charMap.keySet()) { // Create a new input activator InputActivator inputAc = new InputActivator(); // Use linear reference inputAc.entities().add(refs.get(ptr)); // Activate the client InvokerManager im = InvokerManager.of(sessions.get(id).client()); // Get k! final UUID k = refs.get(ptr++); // Register!!! im.closeFuture().add(new FutureCallback() { /* * (non-Javadoc) * * @see * com.indyforge.foxnet.rmi.util.FutureCallback#completed(com * .indyforge.foxnet.rmi.util.Future) */ @Override public void completed(Future future) throws Exception { SpawnDead sd = new SpawnDead(); sd.entities().add(k); server.composite().applyChange(sd); } }); sessions.get(id).client().applyChange(inputAc); } // Reset the network time every where server.composite().applyChange(new ResetNetworkTimeChange()); return sceneProcessor; } public Game copy() { return new Game().assetBundle(assetBundle) .mapPropAssetPath(mapPropAssetPath) .boadcastUpdateTime(broadcastUpdateTime).players(players); } public Scene serverGameScene(List<UUID> refs, float broadcastUpdateTime, String assetBundle, String mapPropAssetPath, Map<Long, Char> playerIds) throws Exception { if (playerIds == null || playerIds.isEmpty()) { throw new IllegalArgumentException("No players ids provided"); } // Delete old refs... refs.clear(); // Create new asset manager using the given zip file AssetManager assets = new AssetManager(new File(assetBundle)); // Use property file Properties properties = new Properties(); // Try to load the given prop file properties.load(assets.open(mapPropAssetPath)); // Parse the width and height int width = Integer.parseInt(properties.getProperty(MAP_WIDTH_PROP)); int height = Integer.parseInt(properties.getProperty(MAP_HEIGHT_PROP)); // Create new scene with the given assets Scene scene = new Scene(assets, Math.round(width + 0.25f * height), height) { /** * */ private static final long serialVersionUID = 1L; @Override protected void onUpdate(float tpf) { super.onUpdate(tpf); if (isSinglePressed(KeyEvent.VK_ESCAPE)) { if (processor().hasSession()) { // Simply terminate the connection InvokerManager.of(processor().session()).close(); } } } }; // Load the char array char[][] map = assets.loadAsset(properties.getProperty(MAP_NAME_KEY), GridLoader.LOADER, true).get(); // Lookup max spawn points int maxSpawns = GridLoader.find(map, SPAWN).size(); /* * Compare max spawn points with the player count. */ if (playerIds.size() > maxSpawns) { throw new IllegalArgumentException("Too many players"); } // Generate the map randomally GridLoader.generate(map, System.nanoTime()); // Put the new sounds scene.soundManager().putSound(EXP_SOUND, properties.getProperty(EXP_SOUND)); scene.soundManager().putSound(EAT_SOUND, properties.getProperty(EAT_SOUND)); scene.soundManager().putSound(GLASS_SOUND, properties.getProperty(GLASS_SOUND)); scene.soundManager().putSound(SHIELD_ON_SOUND, properties.getProperty(SHIELD_ON_SOUND)); scene.soundManager().putSound(SHIELD_OFF_SOUND, properties.getProperty(SHIELD_OFF_SOUND)); scene.soundManager().putSound(PICKUP_SOUND, properties.getProperty(PICKUP_SOUND)); scene.soundManager().putSound(PLACE_SOUND, properties.getProperty(PLACE_SOUND)); scene.soundManager().putSound(MUSIC_SOUND, properties.getProperty(MUSIC_SOUND)); // Preload the next game map scene.addProp(NEXT, copy().mapPropAssetPath(properties.getProperty(NEXT))); // Register the global resources scene.addProp(ACTIVE_FLARE_IMAGE, assets.loadImage( properties.getProperty(ACTIVE_FLARE_IMAGE), true)); scene.addProp(ITEM_INTERFACE, assets.loadImage(properties.getProperty(ITEM_INTERFACE), true)); scene.addProp(DEFAULT_BOMB_IMAGE, assets.loadImage( properties.getProperty(DEFAULT_BOMB_IMAGE), true)); scene.addProp(DEFAULT_BOMB_BAG_IMAGE, assets.loadImage( properties.getProperty(DEFAULT_BOMB_BAG_IMAGE), true)); scene.addProp(NUKE_BOMB_IMAGE, assets.loadImage(properties.getProperty(NUKE_BOMB_IMAGE), true)); scene.addProp(NUKE_BOMB_BAG_IMAGE, assets.loadImage( properties.getProperty(NUKE_BOMB_BAG_IMAGE), true)); scene.addProp(FAST_BOMB_IMAGE, assets.loadImage(properties.getProperty(FAST_BOMB_IMAGE), true)); scene.addProp(FAST_BOMB_BAG_IMAGE, assets.loadImage( properties.getProperty(FAST_BOMB_BAG_IMAGE), true)); scene.addProp(PALISADE_HORI_IMAGE, assets.loadImage( properties.getProperty(PALISADE_HORI_IMAGE), true)); scene.addProp(PALISADE_VERT_IMAGE, assets.loadImage( properties.getProperty(PALISADE_VERT_IMAGE), true)); scene.addProp(PALISADE_BAG_IMAGE, assets.loadImage( properties.getProperty(PALISADE_BAG_IMAGE), true)); scene.addProp(SHIELD_IMAGE, assets.loadImage(properties.getProperty(SHIELD_IMAGE), true)); scene.addProp(SHIELD_POTION_IMAGE, assets.loadImage( properties.getProperty(SHIELD_POTION_IMAGE), true)); scene.addProp(SPEED_IMAGE, assets.loadImage(properties.getProperty(SPEED_IMAGE), true)); scene.addProp(SLOW_SHROOM_IMAGE, assets.loadImage( properties.getProperty(SLOW_SHROOM_IMAGE), true)); scene.addProp(FAST_SHROOM_IMAGE, assets.loadImage( properties.getProperty(FAST_SHROOM_IMAGE), true)); scene.addProp(BREAKABLE_IMAGE, assets.loadImage(properties.getProperty(BREAKABLE_IMAGE), true)); scene.addProp(SOLID_IMAGE, assets.loadImage(properties.getProperty(SOLID_IMAGE), true)); scene.addProp(GROUND_IMAGE, assets.loadImage(properties.getProperty(GROUND_IMAGE), true)); scene.addProp(ESCAPE_IMAGE, assets.loadImage(properties.getProperty(ESCAPE_IMAGE), true)); scene.addProp(CORNER_LD_IMAGE, assets.loadImage(properties.getProperty(CORNER_LD_IMAGE), true)); scene.addProp(CORNER_LU_IMAGE, assets.loadImage(properties.getProperty(CORNER_LU_IMAGE), true)); scene.addProp(CORNER_RD_IMAGE, assets.loadImage(properties.getProperty(CORNER_RD_IMAGE), true)); scene.addProp(CORNER_RU_IMAGE, assets.loadImage(properties.getProperty(CORNER_RU_IMAGE), true)); scene.addProp(WALL_D_IMAGE, assets.loadImage(properties.getProperty(WALL_D_IMAGE), true)); scene.addProp(WALL_U_IMAGE, assets.loadImage(properties.getProperty(WALL_U_IMAGE), true)); scene.addProp(WALL_R_IMAGE, assets.loadImage(properties.getProperty(WALL_R_IMAGE), true)); scene.addProp(WALL_L_IMAGE, assets.loadImage(properties.getProperty(WALL_L_IMAGE), true)); // Parse the width and height of the sprite int spriteWidth = Integer.parseInt(properties .getProperty(EXP_SPRITE_WIDTH)); int spriteHeight = Integer.parseInt(properties .getProperty(EXP_SPRITE_HEIGHT)); // Register the global explosion content scene.addProp( EXP_SPRITE, new Sprite(assets.loadImage(properties.getProperty(EXP_SPRITE), true), spriteWidth, spriteHeight)); // Parse and setup map GraphicsEntity grid = GridLoader.parse(map, scene, width, height, broadcastUpdateTime, System.nanoTime(), playerIds.size() == 1 ? 1 : 2, 0.2f, 0.2f, 0.2f, 0.1f, 0.1f, 0.1f, 0.1f); /* * ******************************************************************** * SETUP THE ITEM INTERFACE STUFF. * ******************************************************************** */ // Load the item interface RenderedImage itemInterface = new RenderedImage( scene.imageProp(ITEM_INTERFACE)); // Calc the item holder width float itemHolderWidth = height * 0.25f; // Set the correct scale itemInterface.scale().set(itemHolderWidth, height); // Move the interface to the right itemInterface.position().x = width; // Attach the item interface scene.attach(itemInterface); // The counter int counter = 0; // Create a new font Resource<Font> font = new TransientSystemFontResource("Verdana", Font.BOLD, 36); // Used to create the text ImageDesc countTextDesc = new ImageDesc().width(64).height(64) .transparency(Transparency.TRANSLUCENT); for (CollectableItem item : CollectableItem.values()) { // Load the item holder RenderedImage itemHolder = new RenderedImage( scene.imageProp(GameRoutines.itemToAsset(item))); // Set scale itemHolder.scale().scaleLocal(itemHolderWidth * 0.5f); // Set position itemHolder.position().set( width + itemHolderWidth * 0.25f, (itemHolderWidth * 0.25f) + itemHolderWidth * 0.5f * counter++); // Attach to scene scene.attach(itemHolder); // Create a new text object Text text = new Text(countTextDesc); // Shift down a bit text.position().y += 0.3f; // Center alignment text.alignment(Alignment.Right); // Set the font text.fontResource(font); // Use red color text.textColor(Color.RED); // Init with X text.text("X"); // Simply attach itemHolder.attach(text); // Add the text as prop scene.addProp(item, text); } /* * ******************************************************************** * INTERFACE STUFF FINISHED * ******************************************************************** */ // The spawn points List<Point> spawnPoints = GridLoader.find(map, GameConstants.SPAWN); /* * Shuffle all spawn points! */ Collections.shuffle(spawnPoints); int i = 0; /* * For all requested players. */ for (Entry<Long, Char> entry : playerIds.entrySet()) { // Create new player as knight GraphicsEntity player = null; /* * Create new char. */ switch (entry.getValue()) { case Dwarf: player = GameRoutines.createRemoteDwarf(assets, String.valueOf(entry.getKey())); break; case Knight: player = GameRoutines.createRemoteKnight(assets, String.valueOf(entry.getKey())); break; case Santa: player = GameRoutines.createRemoteSanta(assets, String.valueOf(entry.getKey())); break; case Wizard: player = GameRoutines.createRemoteWizard(assets, String.valueOf(entry.getKey())); break; default: throw new IllegalArgumentException("Unknown char"); } // Add the registration key to list refs.add(player.registrationKey()); /* * Register to delta position broadcaster. */ scene.typeProp(DeltaPositionBroadcaster.class) .entities() .put(player.registrationKey(), new Vector2f(spawnPoints.get(i))); // Place to spawn grid.childAt(grid.typeProp(Grid.class).index(spawnPoints.get(i++))) .attach(player); } /** * AI TEST * */ // GraphicsEntity aiPlayer = GameRoutines // .createRemoteWizard(assets, "BOT"); // // /* // * Register to delta position broadcaster. // */ // scene.typeProp(DeltaPositionBroadcaster.class) // .entities() // .put(aiPlayer.registrationKey(), // new Vector2f(spawnPoints.get(spawnPoints.size() - 1))); // // // Place to spawn // grid.childAt( // grid.typeProp(Grid.class).index( // spawnPoints.get(spawnPoints.size() - 1))).attach( // aiPlayer); // // Bot bot = new Bot(); // // DefaultAIProcessor proc = new DefaultAIProcessor(new // DefaultAIControl( // aiPlayer), bot); // aiPlayer.attach(proc); /** * AI END */ // Store the player refs scene.addProp(PLAYERS_KEY, new LinkedList<UUID>(refs)); // Store the ids + chars scene.addProp(SESSIONS_KEY, playerIds); // Add the game creator scene.addTypeProp(this); return scene; } }