generated from tilera/1710mod
chore: add original code
This commit is contained in:
parent
da1131909f
commit
b68fd76c8f
42 changed files with 4334 additions and 4 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
.idea
|
||||
build
|
||||
run
|
||||
bin
|
19
LICENSE
Normal file
19
LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2012 Alex "immibis" Campbell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
14
build.gradle
14
build.gradle
|
@ -23,9 +23,9 @@ apply plugin: 'maven-publish'
|
|||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
version = "1.0"
|
||||
group= "modgroup"
|
||||
archivesBaseName = "modid"
|
||||
version = "0.2"
|
||||
group= "tinycarts"
|
||||
archivesBaseName = "com.immibis"
|
||||
|
||||
minecraft {
|
||||
version = "1.7.10-10.13.4.1614-1.7.10"
|
||||
|
@ -34,10 +34,16 @@ minecraft {
|
|||
|
||||
repositories {
|
||||
maven { url = "https://maven.tilera.xyz" }
|
||||
maven {
|
||||
url = "https://s3.tilera.xyz/cdn/minecraft/libs/"
|
||||
metadataSources {
|
||||
artifact()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'com.immibis:immibis-core:59.1.4:deobf'
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
|
65
src/main/java/mods/immibis/subworlds/ClientFakeEntities.java
Normal file
65
src/main/java/mods/immibis/subworlds/ClientFakeEntities.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package mods.immibis.subworlds;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
// maintains a list of fake entities on the client. there is no server equivalent.
|
||||
// on the server, fake entities are updated and destroyed by whatever created them.
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class ClientFakeEntities {
|
||||
private static Map<Integer, FakeEntity> ents = new HashMap<Integer, FakeEntity>();
|
||||
|
||||
public static void debug(String s) {
|
||||
System.out.println("[SubWorlds CFE Debug] "+s);
|
||||
}
|
||||
|
||||
public static void add(FakeEntity ent) {
|
||||
debug("Add CFE "+ent.entityID+": "+ent);
|
||||
ents.put(ent.entityID, ent);
|
||||
}
|
||||
|
||||
public static FakeEntity remove(int entID) {
|
||||
debug("Remove CFE "+entID);
|
||||
return ents.remove(entID);
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
debug("Reset CFEs");
|
||||
ents.clear();
|
||||
}
|
||||
|
||||
public static FakeEntity get(int entID) {
|
||||
return ents.get(entID);
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
FMLCommonHandler.instance().bus().register(new ClientTickHandler());
|
||||
MinecraftForge.EVENT_BUS.register(new EventListener());
|
||||
}
|
||||
|
||||
public static class ClientTickHandler {
|
||||
@SubscribeEvent
|
||||
public void onClientTickEnd(TickEvent.ClientTickEvent evt) {
|
||||
if(evt.phase != TickEvent.Phase.END) return;
|
||||
for(FakeEntity e : ents.values())
|
||||
e.tick();
|
||||
}
|
||||
}
|
||||
|
||||
// must be public or forge throws errors
|
||||
public static class EventListener {
|
||||
@SubscribeEvent
|
||||
public void onRWL(RenderWorldLastEvent evt) {
|
||||
for(FakeEntity e : ents.values())
|
||||
e.renderBase(evt.partialTicks);
|
||||
}
|
||||
}
|
||||
}
|
27
src/main/java/mods/immibis/subworlds/ExitTeleporter.java
Normal file
27
src/main/java/mods/immibis/subworlds/ExitTeleporter.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package mods.immibis.subworlds;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.world.Teleporter;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
public class ExitTeleporter extends Teleporter {
|
||||
public WorldServer world;
|
||||
public double x, y, z;
|
||||
|
||||
public ExitTeleporter(WorldServer par1WorldServer, double x, double y, double z) {
|
||||
super(par1WorldServer);
|
||||
world = par1WorldServer;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void placeInPortal(Entity par1Entity, double par2, double par4, double par6, float par8) {
|
||||
if(par1Entity instanceof EntityLivingBase)
|
||||
((EntityLivingBase)par1Entity).setPositionAndUpdate(x, y, z);
|
||||
else
|
||||
par1Entity.setPosition(x, y, z);
|
||||
}
|
||||
}
|
110
src/main/java/mods/immibis/subworlds/FakeEntity.java
Normal file
110
src/main/java/mods/immibis/subworlds/FakeEntity.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
package mods.immibis.subworlds;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.EntityClientPlayerMP;
|
||||
import net.minecraft.client.renderer.entity.RenderEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.Packet;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* An object which is synced with clients, like an entity, but isn't actually an entity.
|
||||
* They are not automatically associated with a world.
|
||||
*/
|
||||
public abstract class FakeEntity {
|
||||
public abstract Packet getUpdatePacket();
|
||||
public abstract Packet getDescriptionPacket();
|
||||
public abstract Packet getDestructionPacket();
|
||||
|
||||
private static AtomicInteger nextEntityID = new AtomicInteger();
|
||||
|
||||
public final int entityID;
|
||||
public final boolean isClient;
|
||||
|
||||
public FakeEntity(boolean isClient) {
|
||||
entityID = nextEntityID.incrementAndGet();
|
||||
this.isClient = isClient;
|
||||
}
|
||||
|
||||
public FakeEntity(boolean isClient, int entityID) {
|
||||
this.entityID = entityID;
|
||||
this.isClient = isClient;
|
||||
}
|
||||
|
||||
private Set<EntityPlayerMP> trackingPlayers = new HashSet<EntityPlayerMP>();
|
||||
|
||||
public final void setTrackingPlayers(Set<EntityPlayerMP> _new) {
|
||||
for(EntityPlayerMP pl : _new)
|
||||
if(!trackingPlayers.contains(pl)) {
|
||||
Packet packet = getDescriptionPacket();
|
||||
if(packet != null)
|
||||
pl.playerNetServerHandler.netManager.channel().write(packet);
|
||||
}
|
||||
|
||||
for(EntityPlayerMP pl : trackingPlayers)
|
||||
if(!_new.contains(pl)) {
|
||||
Packet packet = getDestructionPacket();
|
||||
if(packet != null)
|
||||
pl.playerNetServerHandler.netManager.channel().write(packet);
|
||||
}
|
||||
|
||||
trackingPlayers.clear();
|
||||
trackingPlayers.addAll(_new);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
if(!isClient) {
|
||||
Packet p = getUpdatePacket();
|
||||
|
||||
if(p != null)
|
||||
for(EntityPlayerMP pl : trackingPlayers)
|
||||
pl.playerNetServerHandler.netManager.channel().write(p);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected static RenderEntity defaultRender;
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected static Entity defaultRenderEntity;
|
||||
|
||||
static {
|
||||
try {
|
||||
RenderEntity rd = new RenderEntity();
|
||||
defaultRender = rd;
|
||||
defaultRenderEntity = new Entity(null) {
|
||||
{
|
||||
boundingBox.setBounds(-1, -1, -1, 1, 1, 1);
|
||||
lastTickPosX = lastTickPosY = lastTickPosZ = 0;
|
||||
}
|
||||
|
||||
@Override protected void entityInit() {}
|
||||
@Override protected void readEntityFromNBT(NBTTagCompound var1) {}
|
||||
@Override protected void writeEntityToNBT(NBTTagCompound var1) {}
|
||||
};
|
||||
} catch(Error e) {
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
// rendering origin is at world coordinates: -pl_x,-pl_y,-pl_z
|
||||
public void render(double pl_x, double pl_y, double pl_z, float partialTick) {
|
||||
defaultRender.doRender(defaultRenderEntity, 3, 3, 3, 0, partialTick);
|
||||
defaultRender.doRender(defaultRenderEntity, -pl_x-2, -pl_y-2, -pl_z-2, 0, partialTick);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
void renderBase(float partialTick) {
|
||||
EntityClientPlayerMP pl = Minecraft.getMinecraft().thePlayer;
|
||||
double pl_x = pl.lastTickPosX + (pl.posX - pl.lastTickPosX) * partialTick;
|
||||
double pl_y = pl.lastTickPosY + (pl.posY - pl.lastTickPosY) * partialTick;
|
||||
double pl_z = pl.lastTickPosZ + (pl.posZ - pl.lastTickPosZ) * partialTick;
|
||||
render(pl_x, pl_y, pl_z, partialTick);
|
||||
}
|
||||
}
|
52
src/main/java/mods/immibis/subworlds/SubWorldsMod.java
Normal file
52
src/main/java/mods/immibis/subworlds/SubWorldsMod.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
package mods.immibis.subworlds;
|
||||
|
||||
import mods.immibis.core.api.porting.SidedProxy;
|
||||
import mods.immibis.subworlds.dw.DWEntity;
|
||||
import mods.immibis.subworlds.dw.DWEntityRenderer;
|
||||
import mods.immibis.subworlds.dw.DWManager;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import cpw.mods.fml.client.registry.RenderingRegistry;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.Mod;
|
||||
import cpw.mods.fml.common.Mod.EventHandler;
|
||||
import cpw.mods.fml.common.Mod.Instance;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.network.FMLNetworkEvent;
|
||||
import cpw.mods.fml.common.registry.EntityRegistry;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@Mod(version="0.0", dependencies="required-after:ImmibisCore", modid=SubWorldsMod.MODID, name="SubWorlds")
|
||||
public class SubWorldsMod {
|
||||
|
||||
public static final String MODID = "SubWorlds";
|
||||
|
||||
@Instance(MODID)
|
||||
public static SubWorldsMod INSTANCE;
|
||||
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onClientConnectedToServer(FMLNetworkEvent.ClientConnectedToServerEvent evt) {
|
||||
ClientFakeEntities.reset();
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static class ClientProxy {
|
||||
public ClientProxy() {
|
||||
ClientFakeEntities.init();
|
||||
RenderingRegistry.registerEntityRenderingHandler(DWEntity.class, new DWEntityRenderer());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void init(FMLInitializationEvent evt) {
|
||||
DWManager.init();
|
||||
MWSManager.init();
|
||||
|
||||
FMLCommonHandler.instance().bus().register(this);
|
||||
|
||||
SidedProxy.instance.createSidedObject("mods.immibis.subworlds.SubWorldsMod$ClientProxy", null);
|
||||
EntityRegistry.registerModEntity(DWEntity.class, "detachedWorld", 0, this, 200, 5, true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import mods.immibis.subworlds.SubWorldsMod;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.ForgeChunkManager;
|
||||
import net.minecraftforge.common.ForgeChunkManager.LoadingCallback;
|
||||
import net.minecraftforge.common.ForgeChunkManager.OrderedLoadingCallback;
|
||||
import net.minecraftforge.common.ForgeChunkManager.Ticket;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
|
||||
public class ChunkLoadingCallback implements LoadingCallback, OrderedLoadingCallback {
|
||||
|
||||
@Override
|
||||
public void ticketsLoaded(List<Ticket> tickets, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Ticket> ticketsLoaded(List<Ticket> tickets, World world, int maxTicketCount) {
|
||||
// do not keep chunks loaded through world reloads
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ChunkLoadingCallback() {
|
||||
try {
|
||||
boolean overridesEnabled = ReflectionHelper.getPrivateValue(ForgeChunkManager.class, null, "overridesEnabled");
|
||||
|
||||
Map<String, Integer> ticketConstraints = ReflectionHelper.getPrivateValue(ForgeChunkManager.class, null, "ticketConstraints");
|
||||
Map<String, Integer> chunkConstraints = ReflectionHelper.getPrivateValue(ForgeChunkManager.class, null, "chunkConstraints");
|
||||
|
||||
if(!overridesEnabled) {
|
||||
ticketConstraints.clear();
|
||||
chunkConstraints.clear();
|
||||
ReflectionHelper.findField(ForgeChunkManager.class, "overridesEnabled").set(null, true);
|
||||
}
|
||||
|
||||
String modid = SubWorldsMod.MODID;
|
||||
|
||||
ticketConstraints.put(modid, Integer.MAX_VALUE);
|
||||
chunkConstraints.put(modid, Integer.MAX_VALUE);
|
||||
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
ForgeChunkManager.setForcedChunkLoadingCallback(SubWorldsMod.INSTANCE, this);
|
||||
}
|
||||
|
||||
}
|
160
src/main/java/mods/immibis/subworlds/dw/DWChunkGenerator.java
Normal file
160
src/main/java/mods/immibis/subworlds/dw/DWChunkGenerator.java
Normal file
|
@ -0,0 +1,160 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.entity.EnumCreatureType;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.IProgressUpdate;
|
||||
import net.minecraft.world.ChunkPosition;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
|
||||
public class DWChunkGenerator implements IChunkProvider {
|
||||
|
||||
public static final BiomeGenBase BIOME = BiomeGenBase.plains;
|
||||
|
||||
public final DWWorldProvider provider;
|
||||
private final int HSIZE; // chunks
|
||||
|
||||
private WorldServer worldObj;
|
||||
//private EmptyChunk emptyChunk;
|
||||
|
||||
public DWChunkGenerator(WorldServer worldObj, DWWorldProvider provider) {
|
||||
this.worldObj = worldObj;
|
||||
this.provider = provider;
|
||||
this.HSIZE = Math.max(provider.props.zsize, provider.props.xsize) / 16;
|
||||
//emptyChunk = new EmptyChunk(worldObj, -10000, -10000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chunkExists(int var1, int var2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk provideChunk(int var1, int var2) {
|
||||
boolean outOfBounds = var1 < 0 || var2 < 0 || var1 >= HSIZE || var2 >= HSIZE;
|
||||
|
||||
// if(outOfBounds) return emptyChunk;
|
||||
|
||||
Chunk chunk = new Chunk(this.worldObj, var1, var2);
|
||||
|
||||
if(!outOfBounds) {
|
||||
|
||||
/*for(int y = 0; y < provider.props.vsize; y++) {
|
||||
if(var1 == 0 && var2 == 0)
|
||||
chunk.setBlockIDWithMetadata(0, y, 0, Block.stone.blockID, 0);
|
||||
if(var1 == HSIZE-1 && var2 == 0)
|
||||
chunk.setBlockIDWithMetadata(15, y, 0, Block.stone.blockID, 0);
|
||||
if(var1 == 0 && var2 == HSIZE-1)
|
||||
chunk.setBlockIDWithMetadata(0, y, 15, Block.stone.blockID, 0);
|
||||
if(var1 == HSIZE-1 && var2 == HSIZE-1)
|
||||
chunk.setBlockIDWithMetadata(15, y, 15, Block.stone.blockID, 0);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 16; x++) {
|
||||
if(var1 == 0) {
|
||||
chunk.setBlockIDWithMetadata(0, 0, x, Block.stone.blockID, 0);
|
||||
chunk.setBlockIDWithMetadata(0, provider.props.vsize-1, x, Block.stone.blockID, 0);
|
||||
}
|
||||
|
||||
if(var1 == HSIZE-1) {
|
||||
chunk.setBlockIDWithMetadata(15, 0, x, Block.stone.blockID, 0);
|
||||
chunk.setBlockIDWithMetadata(15, provider.props.vsize-1, x, Block.stone.blockID, 0);
|
||||
}
|
||||
|
||||
if(var2 == 0) {
|
||||
chunk.setBlockIDWithMetadata(x, 0, 0, Block.stone.blockID, 0);
|
||||
chunk.setBlockIDWithMetadata(x, provider.props.vsize-1, 0, Block.stone.blockID, 0);
|
||||
}
|
||||
if(var2 == HSIZE-1) {
|
||||
chunk.setBlockIDWithMetadata(x, 0, 15, Block.stone.blockID, 0);
|
||||
chunk.setBlockIDWithMetadata(x, provider.props.vsize-1, 15, Block.stone.blockID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for(int x = 0; x < 16; x++)
|
||||
for(int z = 0; z < 16; z++)
|
||||
chunk.setBlockIDWithMetadata(x, 0, z, Block.stone.blockID, 0);*/
|
||||
|
||||
|
||||
int nx = provider.props.xsize/2 - var1 * 16;
|
||||
int nz = provider.props.zsize/2 - var2 * 16;
|
||||
|
||||
for(int dx = 0; dx < 2; dx++)
|
||||
for(int dy = 0; dy < 2; dy++)
|
||||
for(int dz = 0; dz < 2; dz++) {
|
||||
int x = nx+dx, y = provider.props.ysize/2+dy, z = nz+dz;
|
||||
if(x >= 0 && y >= 0 && z >= 0 && x < 16 && y < provider.props.ysize && z < 16)
|
||||
chunk.func_150807_a(x, y, z, Blocks.stone, 0);
|
||||
}
|
||||
}
|
||||
|
||||
chunk.generateSkylightMap();
|
||||
|
||||
Arrays.fill(chunk.getBiomeArray(), (byte)BIOME.biomeID);
|
||||
|
||||
chunk.isTerrainPopulated = true;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk loadChunk(int var1, int var2) {
|
||||
return provideChunk(var1, var2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populate(IChunkProvider var1, int var2, int var3) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveChunks(boolean var1, IProgressUpdate var2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unloadQueuedChunks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSave() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makeString() {
|
||||
return "DWChunkGenerator";
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public List getPossibleCreatures(EnumCreatureType var1, int var2, int var3, int var4) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkPosition func_147416_a(World var1, String var2, int var3, int var4, int var5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoadedChunkCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recreateStructures(int var1, int var2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveExtraData() {
|
||||
}
|
||||
|
||||
}
|
167
src/main/java/mods/immibis/subworlds/dw/DWEntity.java
Normal file
167
src/main/java/mods/immibis/subworlds/dw/DWEntity.java
Normal file
|
@ -0,0 +1,167 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import mods.immibis.subworlds.FakeEntity;
|
||||
import mods.immibis.subworlds.mws.MWSListener;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
/**
|
||||
* DW stands for "Detached World".
|
||||
* Maximum size is always 48x48x48, this cannot easily be changed.
|
||||
* There might be smaller, 16x16x16
|
||||
*/
|
||||
public abstract class DWEntity extends Entity {
|
||||
|
||||
// set of players last known to be tracking this entity which are outside it
|
||||
private Set<EntityPlayerMP> trackingPlayers = new HashSet<EntityPlayerMP>();
|
||||
|
||||
// set of players last known to be inside this entity
|
||||
private Set<EntityPlayerMP> enclosedPlayers = new HashSet<EntityPlayerMP>();
|
||||
|
||||
// fake entity sent to enclosed players to render the external world.
|
||||
private FakeEntity externalWorldFE;
|
||||
|
||||
// internal world, cannot change after initialization
|
||||
private WorldServer internalWorld;
|
||||
|
||||
//private int lastChunkX = Integer.MAX_VALUE, lastChunkZ = Integer.MAX_VALUE;
|
||||
|
||||
public DWEntity(World par1World) {
|
||||
super(par1World);
|
||||
setSize(48, 48);
|
||||
}
|
||||
|
||||
private static final int WATCHER_INDEX_DIMID = 8;
|
||||
|
||||
@Override
|
||||
protected void entityInit() {
|
||||
dataWatcher.addObject(WATCHER_INDEX_DIMID, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readEntityFromNBT(NBTTagCompound var1) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeEntityToNBT(NBTTagCompound var1) {
|
||||
|
||||
}
|
||||
|
||||
protected abstract WorldServer getInternalWorld();
|
||||
protected abstract void updateExternalWorldFE(FakeEntity e);
|
||||
protected abstract FakeEntity createExternalWorldFE();
|
||||
protected abstract void applyGLRotation(float partialTick);
|
||||
|
||||
private boolean requiresInteriorLoaded = false;
|
||||
public boolean requiresInteriorLoaded() {return requiresInteriorLoaded;}
|
||||
|
||||
/*@Override
|
||||
public void setPosition(double par1, double par3, double par5) {
|
||||
}
|
||||
@Override
|
||||
public void setPositionAndRotation(double par1, double par3, double par5, float par7, float par8) {};
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
this.prevPosZ = this.posZ;
|
||||
|
||||
/*if(worldObj.isRemote) {
|
||||
posX = serverPosX / 32.0;
|
||||
posY = serverPosY / 32.0;
|
||||
posZ = serverPosZ / 32.0;
|
||||
}*/
|
||||
|
||||
if(!worldObj.isRemote) {
|
||||
|
||||
|
||||
int lastDimID = (internalWorld == null ? 0 : internalWorld.provider.dimensionId);
|
||||
internalWorld = getInternalWorld();
|
||||
if(internalWorld.provider.dimensionId != lastDimID)
|
||||
dataWatcher.updateObject(WATCHER_INDEX_DIMID, internalWorld.provider.dimensionId);
|
||||
|
||||
// enclosed players see the outside world via MWS
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<EntityPlayerMP> nowEnclosed = new HashSet<EntityPlayerMP>(internalWorld.playerEntities);
|
||||
for(final EntityPlayerMP pl : nowEnclosed)
|
||||
if(!enclosedPlayers.contains(pl)) {
|
||||
MWSManager.getWorldManager(worldObj).addListener(new MWSListener(pl.playerNetServerHandler.netManager) {
|
||||
@Override
|
||||
public void update() {
|
||||
/*x = (int)DWEntity.this.comX;
|
||||
y = (int)DWEntity.this.comY;
|
||||
z = (int)DWEntity.this.comZ;*/
|
||||
x = (int)posX;
|
||||
y = (int)posY;
|
||||
z = (int)posZ;
|
||||
}
|
||||
});
|
||||
}
|
||||
for(final EntityPlayerMP pl : enclosedPlayers)
|
||||
if(!nowEnclosed.contains(pl))
|
||||
MWSManager.getWorldManager(worldObj).removeListener(pl.playerNetServerHandler.netManager);
|
||||
|
||||
enclosedPlayers = nowEnclosed;
|
||||
|
||||
// tracking players see the enclosed world via MWS
|
||||
|
||||
Set<EntityPlayerMP> nowTracking = DWUtils.getTrackingPlayers(this);
|
||||
for(final EntityPlayerMP pl : trackingPlayers)
|
||||
if(!nowTracking.contains(pl))
|
||||
MWSManager.getWorldManager(internalWorld).removeListener(pl.playerNetServerHandler.netManager);
|
||||
trackingPlayers.retainAll(nowTracking);
|
||||
|
||||
for(final EntityPlayerMP pl : nowTracking)
|
||||
if(!trackingPlayers.contains(pl)) {
|
||||
MWSManager.getWorldManager(internalWorld).addListener(new MWSListener(pl.playerNetServerHandler.netManager) {
|
||||
@Override public void update() {}
|
||||
});
|
||||
trackingPlayers.add(pl);
|
||||
}
|
||||
|
||||
requiresInteriorLoaded = enclosedPlayers.size() > 0 || trackingPlayers.size() > 0;
|
||||
|
||||
if(externalWorldFE == null) {
|
||||
externalWorldFE = createExternalWorldFE();
|
||||
}
|
||||
|
||||
//DWWorldProvider provider = (DWWorldProvider)getInternalWorld().provider;
|
||||
|
||||
updateExternalWorldFE(externalWorldFE);
|
||||
externalWorldFE.setTrackingPlayers(enclosedPlayers);
|
||||
externalWorldFE.tick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInRangeToRenderDist(double distsq) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getEnclosedDimensionClient() {
|
||||
return dataWatcher.getWatchableObjectInt(WATCHER_INDEX_DIMID);
|
||||
}
|
||||
|
||||
public void onUnloadOrDestroy() {
|
||||
for(final EntityPlayerMP pl : enclosedPlayers)
|
||||
MWSManager.getWorldManager(worldObj).removeListener(pl.playerNetServerHandler.netManager);
|
||||
if(internalWorld != null)
|
||||
for(final EntityPlayerMP pl : trackingPlayers)
|
||||
MWSManager.getWorldManager(internalWorld).removeListener(pl.playerNetServerHandler.netManager);
|
||||
if(externalWorldFE != null)
|
||||
externalWorldFE.setTrackingPlayers(Collections.<EntityPlayerMP>emptySet());
|
||||
}
|
||||
}
|
406
src/main/java/mods/immibis/subworlds/dw/DWEntityRenderer.java
Normal file
406
src/main/java/mods/immibis/subworlds/dw/DWEntityRenderer.java
Normal file
|
@ -0,0 +1,406 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import mods.immibis.subworlds.mws.MWSClientWorld;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.culling.ClippingHelperImpl;
|
||||
import net.minecraft.client.renderer.culling.Frustrum;
|
||||
import net.minecraft.client.renderer.entity.RenderEntity;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class DWEntityRenderer extends RenderEntity {
|
||||
private static List clipperStack = new ArrayList();
|
||||
private static Field clipperInstanceField;
|
||||
static {
|
||||
clipperInstanceField = ClippingHelperImpl.class.getDeclaredFields()[0];
|
||||
clipperInstanceField.setAccessible(true);
|
||||
}
|
||||
|
||||
public static void pushClipper() {
|
||||
try {
|
||||
clipperStack.add(clipperInstanceField.get(null));
|
||||
clipperInstanceField.set(null, new ClippingHelperImpl());
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void popClipper() {
|
||||
try {
|
||||
clipperInstanceField.set(null, clipperStack.remove(clipperStack.size() - 1));
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRender(Entity ent_, double x, double y, double z, float yaw, float partialTick) {
|
||||
|
||||
DWEntity ent = (DWEntity)ent_;
|
||||
|
||||
double entX = ent.prevPosX + (ent.posX - ent.prevPosX) * partialTick;
|
||||
double entY = ent.prevPosY + (ent.posY - ent.prevPosY) * partialTick;
|
||||
double entZ = ent.prevPosZ + (ent.posZ - ent.prevPosZ) * partialTick;
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glTranslated(x, y, z);
|
||||
|
||||
ent.applyGLRotation(partialTick);
|
||||
|
||||
int dimID = ent.getEnclosedDimensionClient();
|
||||
|
||||
MWSClientWorld subWorld = dimID == 0 ? null : MWSManager.getClientWorld(dimID);
|
||||
if(subWorld == null)
|
||||
super.doRender(ent_, 0, 0, 0, yaw, partialTick);
|
||||
else
|
||||
{
|
||||
//System.out.println(ent.hashCode()+"\t"+ent.entityId+" at "+entX+" "+entY+" "+entZ+" "+ent.world.getBlockId(5, 0, 5));
|
||||
//System.out.println("Render world "+ent.world+" for "+ent.zeppelinID);
|
||||
//GL11.glTranslated(x - entX, y - entY, z - entZ);
|
||||
//GL11.glTranslated(entX - x, entY - y, entZ - z);
|
||||
|
||||
DWWorldProvider pv = (DWWorldProvider)subWorld.provider;
|
||||
GL11.glTranslatef(-pv.props.xsize/2.0f, 0, -pv.props.zsize/2.0f);
|
||||
|
||||
renderClientWorld(subWorld, partialTick, entX, entY, entZ, 0, 0, 0);
|
||||
}
|
||||
GL11.glPopMatrix();
|
||||
|
||||
}
|
||||
|
||||
// e_*: unused.
|
||||
// pl_*: centre of rendered area (we pretend the player is here)
|
||||
// pl_* is also the point in the world that will be rendered at 0,0,0.
|
||||
public static void renderClientWorld(MWSClientWorld world, float partialTick, double e_x, double e_y, double e_z, double pl_x, double pl_y, double pl_z) {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
GL11.glColor3f(1, 1, 1);
|
||||
|
||||
RenderGlobal oldRG = mc.renderGlobal;
|
||||
EntityRenderer oldER = mc.entityRenderer;
|
||||
WorldClient oldWorld = mc.theWorld;
|
||||
mc.renderGlobal = world.render;
|
||||
mc.entityRenderer = world.erender;
|
||||
mc.theWorld = world;
|
||||
int oldPass = MinecraftForgeClient.getRenderPass();
|
||||
pushClipper();
|
||||
|
||||
|
||||
// Pretend the player is at the origin (of the zeppelin world)
|
||||
EntityLivingBase pl = mc.renderViewEntity;
|
||||
double realX = pl.posX, realY = pl.posY, realZ = pl.posZ;
|
||||
double realPrevX = pl.prevPosX, realPrevY = pl.prevPosY, realPrevZ = pl.prevPosZ;
|
||||
double realLastX = pl.lastTickPosX, realLastY = pl.lastTickPosY, realLastZ = pl.lastTickPosZ;
|
||||
pl.posX = pl.prevPosX = pl.lastTickPosX = pl_x;
|
||||
pl.posY = pl.prevPosY = pl.lastTickPosY = pl_y;
|
||||
pl.posZ = pl.prevPosZ = pl.lastTickPosZ = pl_z;
|
||||
|
||||
er_renderWorld(mc.entityRenderer, partialTick, 0);
|
||||
|
||||
popClipper();
|
||||
ForgeHooksClient.setRenderPass(oldPass);
|
||||
mc.theWorld = oldWorld;
|
||||
mc.entityRenderer = oldER;
|
||||
mc.renderGlobal = oldRG;
|
||||
pl.posX = realX;
|
||||
pl.posY = realY;
|
||||
pl.posZ = realZ;
|
||||
pl.prevPosX = realPrevX;
|
||||
pl.prevPosY = realPrevY;
|
||||
pl.prevPosZ = realPrevZ;
|
||||
pl.lastTickPosX = realLastX;
|
||||
pl.lastTickPosY = realLastY;
|
||||
pl.lastTickPosZ = realLastZ;
|
||||
}
|
||||
|
||||
private static void er_renderWorld(EntityRenderer self, float par1, long par2) {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
mc.mcProfiler.startSection("lightTex");
|
||||
|
||||
/*if (self.lightmapUpdateNeeded)
|
||||
{
|
||||
self.updateLightmap(par1);
|
||||
}*/
|
||||
|
||||
GL11.glEnable(GL11.GL_CULL_FACE);
|
||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
|
||||
if (mc.renderViewEntity == null)
|
||||
{
|
||||
mc.renderViewEntity = mc.thePlayer;
|
||||
}
|
||||
|
||||
mc.mcProfiler.endStartSection("pick");
|
||||
//self.getMouseOver(par1);
|
||||
EntityLivingBase entitylivingbase = mc.renderViewEntity;
|
||||
RenderGlobal renderglobal = mc.renderGlobal;
|
||||
EffectRenderer effectrenderer = mc.effectRenderer;
|
||||
double d0 = entitylivingbase.lastTickPosX + (entitylivingbase.posX - entitylivingbase.lastTickPosX) * (double)par1;
|
||||
double d1 = entitylivingbase.lastTickPosY + (entitylivingbase.posY - entitylivingbase.lastTickPosY) * (double)par1;
|
||||
double d2 = entitylivingbase.lastTickPosZ + (entitylivingbase.posZ - entitylivingbase.lastTickPosZ) * (double)par1;
|
||||
mc.mcProfiler.endStartSection("center");
|
||||
|
||||
//for (int j = 0; j < 2; ++j)
|
||||
//{
|
||||
/*if (mc.gameSettings.anaglyph)
|
||||
{
|
||||
anaglyphField = j;
|
||||
|
||||
if (anaglyphField == 0)
|
||||
{
|
||||
GL11.glColorMask(false, true, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL11.glColorMask(true, false, false, false);
|
||||
}
|
||||
}*/
|
||||
|
||||
mc.mcProfiler.endStartSection("clear");
|
||||
//GL11.glViewport(0, 0, mc.displayWidth, mc.displayHeight);
|
||||
//self.updateFogColor(par1);
|
||||
//GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
GL11.glEnable(GL11.GL_CULL_FACE);
|
||||
mc.mcProfiler.endStartSection("camera");
|
||||
//self.setupCameraTransform(par1, j);
|
||||
//ActiveRenderInfo.updateRenderInfo(mc.thePlayer, mc.gameSettings.thirdPersonView == 2);
|
||||
mc.mcProfiler.endStartSection("frustrum");
|
||||
ClippingHelperImpl.getInstance();
|
||||
|
||||
/*if (mc.gameSettings.renderDistance < 2)
|
||||
{
|
||||
self.setupFog(-1, par1);
|
||||
mc.mcProfiler.endStartSection("sky");
|
||||
renderglobal.renderSky(par1);
|
||||
}*/
|
||||
|
||||
//GL11.glEnable(GL11.GL_FOG);
|
||||
//self.setupFog(1, par1);
|
||||
|
||||
if (mc.gameSettings.ambientOcclusion != 0)
|
||||
{
|
||||
GL11.glShadeModel(GL11.GL_SMOOTH);
|
||||
}
|
||||
|
||||
|
||||
mc.mcProfiler.endStartSection("culling");
|
||||
Frustrum frustrum = new Frustrum();
|
||||
frustrum.setPosition(d0, d1, d2);
|
||||
mc.renderGlobal.clipRenderersByFrustum(frustrum, par1);
|
||||
|
||||
|
||||
//if (j == 0)
|
||||
//{
|
||||
mc.mcProfiler.endStartSection("updatechunks");
|
||||
|
||||
while (!mc.renderGlobal.updateRenderers(entitylivingbase, false) && par2 != 0L)
|
||||
{
|
||||
long k = par2 - System.nanoTime();
|
||||
|
||||
if (k < 0L || k > 1000000000L)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
//if (entitylivingbase.posY < 128.0D)
|
||||
//{
|
||||
// self.renderCloudsCheck(renderglobal, par1);
|
||||
//}
|
||||
|
||||
|
||||
mc.mcProfiler.endStartSection("prepareterrain");
|
||||
//self.setupFog(0, par1);
|
||||
//GL11.glEnable(GL11.GL_FOG);
|
||||
mc.getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
mc.mcProfiler.endStartSection("terrain");
|
||||
renderglobal.sortAndRender(entitylivingbase, 0, (double)par1);
|
||||
GL11.glShadeModel(GL11.GL_FLAT);
|
||||
EntityPlayer entityplayer;
|
||||
|
||||
if (self.debugViewDirection == 0)
|
||||
{
|
||||
/* XXX TODO: enable entity rendering inside DW's. renderEntities uses statics that need to be reset afterwards.
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
mc.mcProfiler.endStartSection("entities");
|
||||
ForgeHooksClient.setRenderPass(0);
|
||||
renderglobal.renderEntities(entitylivingbase.getPosition(par1), frustrum, par1);
|
||||
ForgeHooksClient.setRenderPass(0);
|
||||
*/
|
||||
|
||||
/* Forge: Moved down
|
||||
self.enableLightmap((double)par1);
|
||||
mc.mcProfiler.endStartSection("litParticles");
|
||||
effectrenderer.renderLitParticles(entitylivingbase, par1);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
self.setupFog(0, par1);
|
||||
mc.mcProfiler.endStartSection("particles");
|
||||
effectrenderer.renderParticles(entitylivingbase, par1);
|
||||
self.disableLightmap((double)par1);
|
||||
*/
|
||||
|
||||
/*if (mc.objectMouseOver != null && entitylivingbase.isInsideOfMaterial(Material.water) && entitylivingbase instanceof EntityPlayer && !mc.gameSettings.hideGUI)
|
||||
{
|
||||
entityplayer = (EntityPlayer)entitylivingbase;
|
||||
GL11.glDisable(GL11.GL_ALPHA_TEST);
|
||||
mc.mcProfiler.endStartSection("outline");
|
||||
if (!ForgeHooksClient.onDrawBlockHighlight(renderglobal, entityplayer, mc.objectMouseOver, 0, entityplayer.inventory.getCurrentItem(), par1))
|
||||
{
|
||||
renderglobal.drawSelectionBox(entityplayer, mc.objectMouseOver, 0, par1);
|
||||
}
|
||||
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
GL11.glEnable(GL11.GL_CULL_FACE);
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glDepthMask(true);
|
||||
//self.setupFog(0, par1);
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glDisable(GL11.GL_CULL_FACE);
|
||||
mc.getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
|
||||
|
||||
if (mc.gameSettings.fancyGraphics)
|
||||
{
|
||||
mc.mcProfiler.endStartSection("water");
|
||||
|
||||
if (mc.gameSettings.ambientOcclusion != 0)
|
||||
{
|
||||
GL11.glShadeModel(GL11.GL_SMOOTH);
|
||||
}
|
||||
|
||||
GL11.glColorMask(false, false, false, false);
|
||||
int l = renderglobal.sortAndRender(entitylivingbase, 1, (double)par1);
|
||||
|
||||
|
||||
/*if (mc.gameSettings.anaglyph)
|
||||
{
|
||||
if (anaglyphField == 0)
|
||||
{
|
||||
GL11.glColorMask(false, true, true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL11.glColorMask(true, false, false, true);
|
||||
}
|
||||
}
|
||||
else*/
|
||||
|
||||
{
|
||||
GL11.glColorMask(true, true, true, true);
|
||||
}
|
||||
|
||||
if (l > 0)
|
||||
{
|
||||
renderglobal.renderAllRenderLists(1, (double)par1);
|
||||
}
|
||||
|
||||
GL11.glShadeModel(GL11.GL_FLAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
mc.mcProfiler.endStartSection("water");
|
||||
renderglobal.sortAndRender(entitylivingbase, 1, (double)par1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* XXX TODO: enable entity rendering inside DW's. renderEntities uses statics that need to be reset afterwards.
|
||||
if (self.debugViewDirection == 0) //Only render if render pass 0 happens as well.
|
||||
{
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
mc.mcProfiler.endStartSection("entities");
|
||||
ForgeHooksClient.setRenderPass(1);
|
||||
renderglobal.renderEntities(entitylivingbase.getPosition(par1), frustrum, par1);
|
||||
ForgeHooksClient.setRenderPass(-1);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
} */
|
||||
|
||||
GL11.glDepthMask(true);
|
||||
GL11.glEnable(GL11.GL_CULL_FACE);
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
|
||||
/*if (self.cameraZoom == 1.0D && entitylivingbase instanceof EntityPlayer && !mc.gameSettings.hideGUI && mc.objectMouseOver != null && !entitylivingbase.isInsideOfMaterial(Material.water))
|
||||
{
|
||||
entityplayer = (EntityPlayer)entitylivingbase;
|
||||
GL11.glDisable(GL11.GL_ALPHA_TEST);
|
||||
mc.mcProfiler.endStartSection("outline");
|
||||
if (!ForgeHooksClient.onDrawBlockHighlight(renderglobal, entityplayer, mc.objectMouseOver, 0, entityplayer.inventory.getCurrentItem(), par1))
|
||||
{
|
||||
renderglobal.drawSelectionBox(entityplayer, mc.objectMouseOver, 0, par1);
|
||||
}
|
||||
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
||||
}*/
|
||||
|
||||
//mc.mcProfiler.endStartSection("destroyProgress");
|
||||
//GL11.glEnable(GL11.GL_BLEND);
|
||||
//GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
|
||||
//renderglobal.drawBlockDamageTexture(Tessellator.instance, entitylivingbase, par1);
|
||||
//GL11.glDisable(GL11.GL_BLEND);
|
||||
//mc.mcProfiler.endStartSection("weather");
|
||||
//self.renderRainSnow(par1);
|
||||
//GL11.glDisable(GL11.GL_FOG);
|
||||
|
||||
//if (entitylivingbase.posY >= 128.0D)
|
||||
//{
|
||||
// self.renderCloudsCheck(renderglobal, par1);
|
||||
//}
|
||||
|
||||
//Forge: Moved section from above, now particles are the last thing to render.
|
||||
/*self.enableLightmap((double)par1);
|
||||
mc.mcProfiler.endStartSection("litParticles");
|
||||
effectrenderer.renderLitParticles(entitylivingbase, par1);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
//self.setupFog(0, par1);
|
||||
mc.mcProfiler.endStartSection("particles");
|
||||
effectrenderer.renderParticles(entitylivingbase, par1);
|
||||
self.disableLightmap((double)par1);*/
|
||||
//Forge: End Move
|
||||
|
||||
//mc.mcProfiler.endStartSection("FRenderLast");
|
||||
//ForgeHooksClient.dispatchRenderLast(renderglobal, par1);
|
||||
|
||||
//mc.mcProfiler.endStartSection("hand");
|
||||
|
||||
//if (self.cameraZoom == 1.0D)
|
||||
//{
|
||||
// GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
|
||||
// self.renderHand(par1, j);
|
||||
//}
|
||||
|
||||
//if (!mc.gameSettings.anaglyph)
|
||||
//{
|
||||
mc.mcProfiler.endSection();
|
||||
//return;
|
||||
//}
|
||||
//}
|
||||
|
||||
//GL11.glColorMask(true, true, true, false);
|
||||
//mc.mcProfiler.endSection();
|
||||
}
|
||||
|
||||
}
|
231
src/main/java/mods/immibis/subworlds/dw/DWManager.java
Normal file
231
src/main/java/mods/immibis/subworlds/dw/DWManager.java
Normal file
|
@ -0,0 +1,231 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import mods.immibis.core.api.APILocator;
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.core.api.net.IPacketMap;
|
||||
import mods.immibis.core.api.util.NBTType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.IWorldAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldSavedData;
|
||||
import net.minecraft.world.storage.MapStorage;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.network.FMLNetworkEvent;
|
||||
|
||||
public class DWManager {
|
||||
|
||||
// Note: DimensionManager isn't thread safe.
|
||||
// We avoid calling it from the client thread when the integrated server is running.
|
||||
|
||||
public static final int PROVIDER_TYPE_ID = "SpaceCraftMod".hashCode();
|
||||
|
||||
public static final String CHANNEL = "SpaceCraftDW";
|
||||
public static final byte PKT_DIMENSION_LIST = 0;
|
||||
|
||||
private static Map<Integer, WorldProps> registeredDimensions = new HashMap<Integer, WorldProps>();
|
||||
|
||||
private static SaveSpecificData getSaveData() {
|
||||
MapStorage ms = DimensionManager.getWorld(0).mapStorage;
|
||||
SaveSpecificData ssd = (SaveSpecificData)ms.loadData(SaveSpecificData.class, "subworlds-dw-save-data");
|
||||
if(ssd == null)
|
||||
ms.setData("subworlds-dw-save-data", ssd = new SaveSpecificData("subworlds-dw-save-data"));
|
||||
return ssd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty dimension for Detached World use,
|
||||
* returns the dimension ID.
|
||||
* only called on the server
|
||||
*/
|
||||
public static int createWorld(WorldProps props) {
|
||||
int dim = DimensionManager.getNextFreeDimId();
|
||||
|
||||
System.out.println("DWManager: creating dimension #"+dim);
|
||||
|
||||
registerDimensions(Collections.singletonMap(dim, props), false);
|
||||
|
||||
MinecraftServer.getServer().worldServerForDimension(dim);
|
||||
System.out.println("DWManager: created dimension #"+dim);
|
||||
return dim;
|
||||
}
|
||||
public static int createWorld() {
|
||||
return createWorld(new WorldProps());
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
DimensionManager.registerProviderType(PROVIDER_TYPE_ID, DWWorldProvider.class, false);
|
||||
MinecraftForge.EVENT_BUS.register(new EventHandler());
|
||||
FMLCommonHandler.instance().bus().register(new ConnectionHandler());
|
||||
APILocator.getNetManager().listen(new PacketMap());
|
||||
new ChunkLoadingCallback();
|
||||
}
|
||||
|
||||
private static class PacketMap implements IPacketMap {
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket createS2CPacket(byte id) {
|
||||
if(id == PKT_DIMENSION_LIST)
|
||||
return new PacketDWDimensionList();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket createC2SPacket(byte id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ConnectionHandler {
|
||||
@SubscribeEvent
|
||||
public String connectionReceived(FMLNetworkEvent.ServerConnectionFromClientEvent evt) {
|
||||
PacketDWDimensionList packet = new PacketDWDimensionList();
|
||||
packet.clearExisting = true;
|
||||
packet.data = registeredDimensions;
|
||||
APILocator.getNetManager().send(packet, evt.manager, true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// only called on the server, unless there is no server
|
||||
@SuppressWarnings("unchecked")
|
||||
static void registerDimensions(Map<Integer, WorldProps> dimIDs, boolean clearExisting) {
|
||||
if(clearExisting) {
|
||||
for(int i : registeredDimensions.keySet())
|
||||
DimensionManager.unregisterDimension(i);
|
||||
registeredDimensions.clear();
|
||||
}
|
||||
SaveSpecificData sd = MinecraftServer.getServer() == null ? null : getSaveData();
|
||||
for(int i : dimIDs.keySet()) {
|
||||
DimensionManager.registerDimension(i, PROVIDER_TYPE_ID);
|
||||
registeredDimensions.put(i, dimIDs.get(i));
|
||||
|
||||
if(sd != null && !sd.dw_worlds.containsKey(i)) {
|
||||
sd.dw_worlds.put(i, dimIDs.get(i));
|
||||
sd.setDirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(sd != null)
|
||||
{
|
||||
PacketDWDimensionList packet = new PacketDWDimensionList();
|
||||
packet.clearExisting = clearExisting;
|
||||
packet.data = dimIDs;
|
||||
for(EntityPlayer pl : (List<EntityPlayer>)MinecraftServer.getServer().getConfigurationManager().playerEntityList) {
|
||||
APILocator.getNetManager().sendToClient(packet, pl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// must be public or Forge crashes
|
||||
public static class EventHandler {
|
||||
@SubscribeEvent
|
||||
public void onWorldLoad(WorldEvent.Load evt) {
|
||||
if(!evt.world.isRemote && evt.world.provider.dimensionId == 0) {
|
||||
registerDimensions(getSaveData().dw_worlds, true);
|
||||
}
|
||||
if(!evt.world.isRemote)
|
||||
evt.world.addWorldAccess(new WorldListener(evt.world));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onWorldUnload(WorldEvent.Unload evt) {
|
||||
if(!evt.world.isRemote && evt.world.provider.dimensionId == 0) {
|
||||
registerDimensions(Collections.<Integer, WorldProps>emptyMap(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// must be public as instances are created by reflection
|
||||
public static class SaveSpecificData extends WorldSavedData {
|
||||
public SaveSpecificData(String par1Str) {
|
||||
super(par1Str);
|
||||
}
|
||||
|
||||
public Map<Integer, WorldProps> dw_worlds = new HashMap<Integer, WorldProps>();
|
||||
|
||||
@Override
|
||||
public void readFromNBT(NBTTagCompound var1) {
|
||||
if(var1.hasKey("dw_worlds")) {
|
||||
NBTTagList t = var1.getTagList("dw_worlds", NBTType.COMPOUND);
|
||||
for(int k = 0; k < t.tagCount(); k++)
|
||||
{
|
||||
WorldProps props = new WorldProps();
|
||||
NBTTagCompound tag = t.getCompoundTagAt(k);
|
||||
int dim = tag.getInteger("dim");
|
||||
props.read(tag);
|
||||
dw_worlds.put(dim, props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(NBTTagCompound var1) {
|
||||
NBTTagList t = new NBTTagList();
|
||||
for(Map.Entry<Integer, WorldProps> i : dw_worlds.entrySet()) {
|
||||
NBTTagCompound c = new NBTTagCompound();
|
||||
c.setInteger("dim", i.getKey());
|
||||
i.getValue().write(c);
|
||||
t.appendTag(c);
|
||||
}
|
||||
var1.setTag("dw_worlds", t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class WorldListener implements IWorldAccess {
|
||||
//public final World worldObj;
|
||||
public WorldListener(World world) {
|
||||
//this.worldObj = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityDestroy(Entity var1) {
|
||||
if(var1 instanceof DWEntity)
|
||||
((DWEntity)var1).onUnloadOrDestroy();
|
||||
}
|
||||
|
||||
@Override public void markBlockForUpdate(int var1, int var2, int var3) {}
|
||||
@Override public void markBlockForRenderUpdate(int var1, int var2, int var3) {}
|
||||
@Override public void markBlockRangeForRenderUpdate(int var1, int var2, int var3, int var4, int var5, int var6) {}
|
||||
@Override public void playSound(String var1, double var2, double var4, double var6, float var8, float var9) {}
|
||||
@Override public void playSoundToNearExcept(EntityPlayer var1, String var2, double var3, double var5, double var7, float var9, float var10) {}
|
||||
@Override public void spawnParticle(String var1, double var2, double var4, double var6, double var8, double var10, double var12) {}
|
||||
@Override public void onEntityCreate(Entity var1) {}
|
||||
@Override public void playRecord(String var1, int var2, int var3, int var4) {}
|
||||
@Override public void broadcastSound(int var1, int var2, int var3, int var4, int var5) {}
|
||||
@Override public void playAuxSFX(EntityPlayer var1, int var2, int var3, int var4, int var5, int var6) {}
|
||||
@Override public void destroyBlockPartially(int var1, int var2, int var3, int var4, int var5) {}
|
||||
@Override public void onStaticEntitiesChanged() {}
|
||||
}
|
||||
|
||||
public static WorldProps getProps(int dim) {
|
||||
WorldProps p = registeredDimensions.get(dim);
|
||||
if(p == null)
|
||||
return new WorldProps(); // probably on client. TODO verify correct
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
31
src/main/java/mods/immibis/subworlds/dw/DWTeleporter.java
Normal file
31
src/main/java/mods/immibis/subworlds/dw/DWTeleporter.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.world.Teleporter;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
public class DWTeleporter extends Teleporter {
|
||||
|
||||
public WorldServer world;
|
||||
|
||||
public DWTeleporter(WorldServer par1WorldServer) {
|
||||
super(par1WorldServer);
|
||||
world = par1WorldServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void placeInPortal(Entity par1Entity, double par2, double par4, double par6, float par8) {
|
||||
DWWorldProvider provider = (DWWorldProvider)world.provider;
|
||||
|
||||
double x = provider.props.xsize/2;
|
||||
double y = 5;
|
||||
double z = provider.props.zsize/2;
|
||||
|
||||
if(par1Entity instanceof EntityLivingBase)
|
||||
((EntityLivingBase)par1Entity).setPositionAndUpdate(x, y, z);
|
||||
else
|
||||
par1Entity.setPosition(x, y, z);
|
||||
}
|
||||
|
||||
}
|
22
src/main/java/mods/immibis/subworlds/dw/DWUtils.java
Normal file
22
src/main/java/mods/immibis/subworlds/dw/DWUtils.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityTracker;
|
||||
import net.minecraft.entity.EntityTrackerEntry;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.util.IntHashMap;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
|
||||
public class DWUtils {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Set<EntityPlayerMP> getTrackingPlayers(Entity ent) {
|
||||
EntityTracker t = ((WorldServer)ent.worldObj).getEntityTracker();
|
||||
|
||||
IntHashMap trackedEntityIDs = ReflectionHelper.getPrivateValue(EntityTracker.class, t, 3);
|
||||
EntityTrackerEntry entry = (EntityTrackerEntry)trackedEntityIDs.lookup(ent.getEntityId());
|
||||
return entry.trackingPlayers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.world.ChunkPosition;
|
||||
import net.minecraft.world.WorldType;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.biome.WorldChunkManager;
|
||||
import net.minecraft.world.gen.layer.GenLayer;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class DWWorldChunkManager extends WorldChunkManager {
|
||||
public final DWWorldProvider provider;
|
||||
|
||||
public DWWorldChunkManager(DWWorldProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areBiomesViable(int par1, int par2, int par3, List par4List) {
|
||||
return par4List.contains(DWChunkGenerator.BIOME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkPosition findBiomePosition(int par1, int par2, int par3, List par4List, Random par5Random) {
|
||||
if(par4List.contains(DWChunkGenerator.BIOME))
|
||||
return new ChunkPosition(provider.props.xsize/2, provider.props.ysize/2, provider.props.zsize/2);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeGenBase[] getBiomeGenAt(BiomeGenBase[] ar, int par2, int par3, int par4, int par5, boolean par6) {
|
||||
if (ar == null || ar.length < par4 * par5)
|
||||
ar = new BiomeGenBase[par4 * par5];
|
||||
|
||||
Arrays.fill(ar, DWChunkGenerator.BIOME);
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeGenBase getBiomeGenAt(int par1, int par2) {
|
||||
return DWChunkGenerator.BIOME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeGenBase[] getBiomesForGeneration(BiomeGenBase[] ar, int par2, int par3, int par4, int par5) {
|
||||
if (ar == null || ar.length < par4 * par5)
|
||||
ar = new BiomeGenBase[par4 * par5];
|
||||
|
||||
Arrays.fill(ar, DWChunkGenerator.BIOME);
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List getBiomesToSpawnIn() {
|
||||
return Collections.singletonList(DWChunkGenerator.BIOME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenLayer[] getModdedBiomeGenerators(WorldType worldType, long seed, GenLayer[] original) {
|
||||
return original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] getRainfall(float[] ar, int par2, int par3, int par4, int par5) {
|
||||
if(ar == null || ar.length < par4 * par5)
|
||||
ar = new float[par4 * par5];
|
||||
|
||||
Arrays.fill(ar, DWChunkGenerator.BIOME.rainfall);
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTemperatureAtHeight(float par1, int par2) {
|
||||
return par1;
|
||||
}
|
||||
}
|
226
src/main/java/mods/immibis/subworlds/dw/DWWorldProvider.java
Normal file
226
src/main/java/mods/immibis/subworlds/dw/DWWorldProvider.java
Normal file
|
@ -0,0 +1,226 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.util.ChunkCoordinates;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.WorldProvider;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class DWWorldProvider extends WorldProvider {
|
||||
|
||||
public WorldProps props;
|
||||
|
||||
public static final boolean
|
||||
LIGHTNING = false,
|
||||
RAIN = false,
|
||||
RESPAWN_HERE = false,
|
||||
FOG = false,
|
||||
FULLBRIGHT = true;
|
||||
|
||||
public DWTeleporter teleporter;
|
||||
|
||||
@Override
|
||||
public void setDimension(int dim) {
|
||||
props = DWManager.getProps(dim);
|
||||
super.setDimension(dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public Vec3 getSkyColor(Entity cameraEntity, float partialTicks) {
|
||||
return super.getSkyColor(cameraEntity, partialTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDimensionName() {
|
||||
return "Detached World";
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float[] calcSunriseSunsetColors(float par1, float par2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCoordinateBeSpawn(int par1, int par2) {
|
||||
return par1 >= 0 && par1 < props.xsize && par2 >= 0 && par2 < props.zsize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDoLightning(Chunk chunk) {
|
||||
return LIGHTNING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDoRainSnowIce(Chunk chunk) {
|
||||
return RAIN;
|
||||
}
|
||||
|
||||
/*@Override
|
||||
public boolean canMineBlock(EntityPlayer player, int x, int y, int z) {
|
||||
return x >= 0 && y >= 0 && z >= 0 && x < HSIZE && y < VSIZE && z < HSIZE && super.canMineBlock(player, x, y, z);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public boolean canRespawnHere() {
|
||||
return RESPAWN_HERE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkProvider createChunkGenerator() {
|
||||
try {
|
||||
return props.generatorClass.getConstructor(WorldServer.class, DWWorldProvider.class).newInstance((WorldServer)worldObj, this);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
//new DWChunkGenerator((WorldServer)worldObj, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean doesXZShowFog(int par1, int par2) {
|
||||
return FOG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateLightBrightnessTable() {
|
||||
if(FULLBRIGHT) {
|
||||
for(int k = 0; k < 16; k++)
|
||||
lightBrightnessTable[k] = 1;
|
||||
} else
|
||||
super.generateLightBrightnessTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActualHeight() {
|
||||
return props.ysize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAverageGroundLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeGenBase getBiomeGenForCoords(int x, int z) {
|
||||
return DWChunkGenerator.BIOME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public Vec3 getFogColor(float par1, float par2) {
|
||||
//return worldObj.getWorldVec3Pool().getVecFromPool((int)(par1*255), 255, (int)(par2*255));
|
||||
return super.getFogColor(par1, par2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return props.ysize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkCoordinates getRandomizedSpawnPoint() {
|
||||
return new ChunkCoordinates(props.xsize/2, props.ysize/2, props.zsize/2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRespawnDimension(EntityPlayerMP player) {
|
||||
return RESPAWN_HERE ? dimensionId : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSaveFolder() {
|
||||
return "CRAFT" + dimensionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSeed() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkCoordinates getSpawnPoint() {
|
||||
return getRandomizedSpawnPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public double getVoidFogYFactor() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWelcomeMessage() {
|
||||
return "Entering sub-world...";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDepartMessage() {
|
||||
return "Leaving sub-world...";
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean getWorldHasVoidParticles() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDaytime() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSurfaceWorld() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerWorldChunkManager() {
|
||||
worldChunkMgr = new DWWorldChunkManager(this);
|
||||
if(!worldObj.isRemote)
|
||||
teleporter = new DWTeleporter((WorldServer)worldObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAllowedSpawnTypes(boolean allowHostile, boolean allowPeaceful) {
|
||||
super.setAllowedSpawnTypes(false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWeather() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSnowAt(int x, int y, int z, boolean checkLight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBlockFreeze(int x, int y, int z, boolean byWater) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMineBlock(EntityPlayer player, int x, int y, int z) {
|
||||
return super.canMineBlock(player, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float calculateCelestialAngle(long par1, float par3) {
|
||||
return super.calculateCelestialAngle(par1, par3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateInitialWeather() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.core.api.net.PacketUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
public class PacketDWDimensionList implements IPacket {
|
||||
|
||||
public boolean clearExisting = false;
|
||||
public Map<Integer, WorldProps> data = new HashMap<Integer, WorldProps>();
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return DWManager.PKT_DIMENSION_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return DWManager.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
clearExisting = in.readBoolean();
|
||||
int len = in.readInt();
|
||||
for(int k = 0; k < len; k++) {
|
||||
int id = in.readInt();
|
||||
WorldProps wp = new WorldProps();
|
||||
wp.read(PacketUtils.readNBT(in));
|
||||
data.put(id, wp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeBoolean(clearExisting);
|
||||
out.writeInt(data.size());
|
||||
for(Map.Entry<Integer, WorldProps> e : data.entrySet()) {
|
||||
out.writeInt(e.getKey());
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
e.getValue().write(tag);
|
||||
PacketUtils.writeNBT(tag, out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceived(EntityPlayer source) {
|
||||
if(source == null && MinecraftServer.getServer() == null) {
|
||||
DWManager.registerDimensions(data, clearExisting);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
32
src/main/java/mods/immibis/subworlds/dw/WorldProps.java
Normal file
32
src/main/java/mods/immibis/subworlds/dw/WorldProps.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package mods.immibis.subworlds.dw;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
|
||||
// POD structure with extra info about a DW world
|
||||
public final class WorldProps {
|
||||
public int xsize = 48;
|
||||
public int ysize = 48;
|
||||
public int zsize = 48;
|
||||
|
||||
// class must have constructor taking (WorldServer, DWWorldProvider)
|
||||
public Class<? extends IChunkProvider> generatorClass = DWChunkGenerator.class;
|
||||
|
||||
public void read(NBTTagCompound tag) {
|
||||
xsize = tag.getInteger("xsize");
|
||||
ysize = tag.getInteger("ysize");
|
||||
zsize = tag.getInteger("zsize");
|
||||
try {
|
||||
generatorClass = Class.forName(tag.getString("genclass")).asSubclass(IChunkProvider.class);
|
||||
} catch(ClassNotFoundException e) {
|
||||
generatorClass = DWChunkGenerator.class;
|
||||
}
|
||||
}
|
||||
|
||||
public void write(NBTTagCompound tag) {
|
||||
tag.setInteger("xsize", xsize);
|
||||
tag.setInteger("ysize", ysize);
|
||||
tag.setInteger("zsize", zsize);
|
||||
tag.setString("genclass", generatorClass.getName());
|
||||
}
|
||||
}
|
79
src/main/java/mods/immibis/subworlds/mws/MWSClientWorld.java
Normal file
79
src/main/java/mods/immibis/subworlds/mws/MWSClientWorld.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
package mods.immibis.subworlds.mws;
|
||||
|
||||
|
||||
import mods.immibis.subworlds.dw.DWWorldProvider;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.world.EnumDifficulty;
|
||||
import net.minecraft.world.WorldSettings;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class MWSClientWorld extends WorldClient {
|
||||
public int dimension;
|
||||
|
||||
//private Chunk blankChunk;
|
||||
|
||||
public boolean isDead = false;
|
||||
|
||||
public MWSClientWorld(int dimID) {
|
||||
// need a valid NetClientHandler for construction so grab one from the real world
|
||||
super((NetHandlerPlayClient)ReflectionHelper.getPrivateValue(WorldClient.class, Minecraft.getMinecraft().theWorld, 0),
|
||||
new WorldSettings(Minecraft.getMinecraft().theWorld.getWorldInfo()),
|
||||
dimID,
|
||||
EnumDifficulty.PEACEFUL, // difficulty
|
||||
Minecraft.getMinecraft().theWorld.theProfiler);
|
||||
|
||||
// but now we don't need it any more
|
||||
ReflectionHelper.setPrivateValue(WorldClient.class, this, null, 0);
|
||||
|
||||
dimension = dimID;
|
||||
|
||||
isRemote = true;
|
||||
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
render = new RenderGlobal(mc); /*{
|
||||
@Override
|
||||
public void renderAllRenderLists(int par1, double par2) {
|
||||
super.renderAllRenderLists(par1, par2);
|
||||
System.out.println(par1+" "+par2+" "+((java.util.List)ReflectionHelper.getPrivateValue(RenderGlobal.class, this, "glRenderLists")).size());
|
||||
}
|
||||
};*/
|
||||
final EntityRenderer normalER = mc.entityRenderer;
|
||||
erender = new EntityRenderer(mc, mc.getResourceManager()) {
|
||||
|
||||
// use the normal lightmap, not our separate one
|
||||
@Override public void disableLightmap(double par1) {normalER.disableLightmap(par1);}
|
||||
@Override public void enableLightmap(double par1) {normalER.enableLightmap(par1);}
|
||||
};
|
||||
|
||||
render.setWorldAndLoadRenderers(this);
|
||||
|
||||
//blankChunk = getChunkFromChunkCoords(0, 0);
|
||||
|
||||
if(provider instanceof DWWorldProvider) {
|
||||
DWWorldProvider pv = (DWWorldProvider)provider;
|
||||
|
||||
for(int x = -1; x <= pv.props.xsize; x++)
|
||||
for(int z = -1; z <= pv.props.zsize; z++)
|
||||
doPreChunk(x, z, true);
|
||||
}
|
||||
}
|
||||
|
||||
public RenderGlobal render;
|
||||
public EntityRenderer erender;
|
||||
|
||||
public void zeppelinTick() {
|
||||
updateEntities();
|
||||
}
|
||||
|
||||
public void unloadChunk(int x, int z) {
|
||||
doPreChunk(x, z, false);
|
||||
}
|
||||
}
|
34
src/main/java/mods/immibis/subworlds/mws/MWSListener.java
Normal file
34
src/main/java/mods/immibis/subworlds/mws/MWSListener.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
package mods.immibis.subworlds.mws;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.world.ChunkCoordIntPair;
|
||||
|
||||
|
||||
/**
|
||||
* Contains a reference to a client, as well as a
|
||||
* mechanism for determining which part of the world to send to this client.
|
||||
*/
|
||||
public abstract class MWSListener {
|
||||
public final NetworkManager client;
|
||||
|
||||
public MWSListener(NetworkManager client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
// See update()
|
||||
public int x, y, z;
|
||||
public boolean isDead;
|
||||
|
||||
public int ticksToNextRangeCheck = 0;
|
||||
public int RANGE_CHECK_INTERVAL = 20;
|
||||
Set<ChunkCoordIntPair> loadedChunks = new HashSet<ChunkCoordIntPair>();
|
||||
|
||||
/**
|
||||
* Override this to update x, y and z with the centre of the area that will be sent to the client.
|
||||
* Set isDead to true to remove the listener.
|
||||
*/
|
||||
public abstract void update();
|
||||
}
|
204
src/main/java/mods/immibis/subworlds/mws/MWSManager.java
Normal file
204
src/main/java/mods/immibis/subworlds/mws/MWSManager.java
Normal file
|
@ -0,0 +1,204 @@
|
|||
package mods.immibis.subworlds.mws;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import mods.immibis.core.api.APILocator;
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.core.api.net.IPacketMap;
|
||||
import mods.immibis.core.api.net.IPacketWrapper;
|
||||
import mods.immibis.subworlds.mws.packets.*;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent;
|
||||
import cpw.mods.fml.common.network.FMLNetworkEvent;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* MWS is Multi-World Sync. It handles sending worlds to clients that the player isn't in.
|
||||
*
|
||||
* Each server world is associated with an MWSWorldManager, even if no clients are watching it.
|
||||
*/
|
||||
public class MWSManager {
|
||||
|
||||
public static void debug(String s) {
|
||||
System.out.println("[SubWorlds MWS Debug] "+s);
|
||||
}
|
||||
|
||||
public static final String CHANNEL = "ImmMWS";
|
||||
|
||||
private static WeakHashMap<World, MWSWorldManager> managers = new WeakHashMap<World, MWSWorldManager>();
|
||||
|
||||
/**
|
||||
* Returns the MWSWorldManager that controls MWS for a given server world.
|
||||
*/
|
||||
public static MWSWorldManager getWorldManager(World world) {
|
||||
if(world.isRemote)
|
||||
throw new IllegalArgumentException("Argument must be a server world.");
|
||||
|
||||
MWSWorldManager m = managers.get(world);
|
||||
if(m == null)
|
||||
managers.put(world, m = new MWSWorldManager(world));
|
||||
return m;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
private static Map<Integer, MWSClientWorld> clientWorlds;
|
||||
static {
|
||||
try {
|
||||
clientWorlds = new HashMap<Integer, MWSClientWorld>();
|
||||
} catch(NoSuchFieldError e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MWSClientWorld for a given dimension ID, or null if none exists.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static MWSClientWorld getClientWorld(int dimID) {
|
||||
return clientWorlds.get(dimID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static void clientBegin(int dimID) {
|
||||
debug("MWS client start: "+dimID);
|
||||
clientWorlds.put(dimID, new MWSClientWorld(dimID));
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static void clientEnd(int dimID) {
|
||||
debug("MWS client end: "+dimID);
|
||||
MWSClientWorld w = clientWorlds.remove(dimID);
|
||||
if(w != null) {
|
||||
// is any cleanup necessary?
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static Entity findClientEntity(int entID) {
|
||||
for(MWSClientWorld w : clientWorlds.values()) {
|
||||
Entity e = w.getEntityByID(entID);
|
||||
if(e != null)
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static void init() {
|
||||
MinecraftForge.EVENT_BUS.register(new ForgeEventListener());
|
||||
APILocator.getNetManager().listen(new PacketMap());
|
||||
FMLCommonHandler.instance().bus().register(new FMLEventListener());
|
||||
}
|
||||
|
||||
// must be public or Forge throws an exception
|
||||
public static class ForgeEventListener {
|
||||
@SubscribeEvent
|
||||
public void onWorldUnload(WorldEvent.Unload evt) {
|
||||
if(!evt.world.isRemote) {
|
||||
MWSWorldManager m = managers.get(evt.world);
|
||||
if(m != null)
|
||||
m.onWorldUnload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final byte PKT_BEGIN = 0;
|
||||
public static final byte PKT_BLOCK = 1;
|
||||
public static final byte PKT_CHUNK = 2;
|
||||
public static final byte PKT_MULTIBLOCK = 3;
|
||||
public static final byte PKT_TILE = 4;
|
||||
public static final byte PKT_UNLOAD = 5;
|
||||
public static final byte PKT_END = 6;
|
||||
public static final byte PKT_SET_WORLD = 7;
|
||||
|
||||
private static class PacketMap implements IPacketMap {
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket createS2CPacket(byte id) {
|
||||
switch(id) {
|
||||
case PKT_BEGIN: return new PacketMWSBegin();
|
||||
case PKT_BLOCK: return new PacketMWSBlock();
|
||||
case PKT_CHUNK: return new PacketMWSChunk();
|
||||
case PKT_MULTIBLOCK: return new PacketMWSMultiBlock();
|
||||
case PKT_TILE: return new PacketMWSTile();
|
||||
case PKT_UNLOAD: return new PacketMWSUnload();
|
||||
case PKT_END: return new PacketMWSEnd();
|
||||
case PKT_SET_WORLD: return new PacketMWSSetWorld();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket createC2SPacket(byte id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// must be public or forge crashes
|
||||
public static class FMLEventListener {
|
||||
@SubscribeEvent
|
||||
public void onServerTickEnd(TickEvent.ServerTickEvent evt) {
|
||||
if(evt.phase != TickEvent.Phase.END) return;
|
||||
for(MWSWorldManager m : managers.values())
|
||||
m.tick();
|
||||
}
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onClientSideConnect(FMLNetworkEvent.ClientConnectedToServerEvent evt) {
|
||||
evt.manager.channel().pipeline().addBefore("packet_handler", "immibis subworlds mws subworld packet delayer congratulations if you are reading this far", new ChannelInboundHandlerAdapter() {
|
||||
boolean delayingMessages = false;
|
||||
int delayingMessagesForWorld;
|
||||
List<Object> delayedMessages = new ArrayList<>();
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if(msg instanceof IPacketWrapper) {
|
||||
IPacket wp = ((IPacketWrapper)msg).packet;
|
||||
if(wp instanceof PacketMWSSetWorld) {
|
||||
int dim = ((PacketMWSSetWorld)wp).dim;
|
||||
if(delayingMessages && dim != delayingMessagesForWorld) {
|
||||
delayingMessages = false;
|
||||
delayedMessages.add(new IPacketWrapper(new PacketMWSSetWorld(PacketMWSSetWorld.NORMAL_DIM)));
|
||||
for(Object obj : delayedMessages)
|
||||
ctx.fireChannelRead(obj);
|
||||
delayedMessages.clear();
|
||||
}
|
||||
if(dim != PacketMWSSetWorld.NORMAL_DIM) {
|
||||
delayingMessages = true;
|
||||
delayingMessagesForWorld = dim;
|
||||
delayedMessages.add(msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(delayingMessages)
|
||||
delayedMessages.add(msg);
|
||||
else
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
457
src/main/java/mods/immibis/subworlds/mws/MWSWorldManager.java
Normal file
457
src/main/java/mods/immibis/subworlds/mws/MWSWorldManager.java
Normal file
|
@ -0,0 +1,457 @@
|
|||
package mods.immibis.subworlds.mws;
|
||||
|
||||
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import mods.immibis.core.api.APILocator;
|
||||
import mods.immibis.subworlds.dw.DWWorldProvider;
|
||||
import mods.immibis.subworlds.mws.packets.*;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.LongHashMap;
|
||||
import net.minecraft.world.ChunkCoordIntPair;
|
||||
import net.minecraft.world.IWorldAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
/**
|
||||
* Holds MWS state for one world.
|
||||
*/
|
||||
public class MWSWorldManager {
|
||||
private final WeakReference<World> worldObj;
|
||||
private final int dimensionID; // if world is unloaded, we need to know the dimension number to inform clients
|
||||
|
||||
private final int VIEW_DISTANCE = MinecraftServer.getServer().getConfigurationManager().getViewDistance();
|
||||
|
||||
MWSWorldManager(World world) {
|
||||
this.worldObj = new WeakReference<World>(world);
|
||||
this.dimensionID = world.provider.dimensionId;
|
||||
world.addWorldAccess(new WorldListener());
|
||||
}
|
||||
|
||||
private class Range {
|
||||
// inclusive min, exclusive max
|
||||
public final int minx, miny, minz, maxx, maxy, maxz;
|
||||
public Range(int minx, int miny, int minz, int maxx, int maxy, int maxz) {
|
||||
this.minx = minx;
|
||||
this.miny = miny;
|
||||
this.minz = minz;
|
||||
this.maxx = maxx;
|
||||
this.maxy = maxy;
|
||||
this.maxz = maxz;
|
||||
}
|
||||
|
||||
public int getBlockCount() {
|
||||
return (maxx - minx) * (maxy - miny) * (maxz - minz);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<MWSListener> listeners = new HashSet<MWSListener>();
|
||||
|
||||
private class SyncedChunk {
|
||||
public final int x, z;
|
||||
|
||||
public SyncedChunk(int x, int z) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
private Range[] updateRanges = new Range[8];
|
||||
private int nUpdateRanges;
|
||||
private int nUpdatedBlocks;
|
||||
|
||||
//public Set<MWSListener> listeners = new HashSet<MWSListener>();
|
||||
|
||||
public void addRange(Range r) {
|
||||
if(nUpdateRanges < updateRanges.length) {
|
||||
updateRanges[nUpdateRanges] = r;
|
||||
nUpdatedBlocks += r.getBlockCount();
|
||||
}
|
||||
nUpdateRanges++;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<Packet> nextUpdatePackets() {
|
||||
if(nUpdateRanges == 0)
|
||||
return null;
|
||||
|
||||
World world = worldObj.get();
|
||||
if(world == null)
|
||||
return null;
|
||||
|
||||
Collection<Packet> rv = null;
|
||||
|
||||
if(nUpdatedBlocks == 1) {
|
||||
int x = updateRanges[0].minx + (this.x << 4);
|
||||
int y = updateRanges[0].miny;
|
||||
int z = updateRanges[0].minz + (this.z << 4);
|
||||
|
||||
updateRanges[0] = null;
|
||||
|
||||
Packet blockPacket = APILocator.getNetManager().wrap(new PacketMWSBlock(x, y, z, world), true);
|
||||
|
||||
TileEntity te = world.getTileEntity(x, y, z);
|
||||
Packet tedesc = te == null ? null : te.getDescriptionPacket();
|
||||
if(tedesc != null)
|
||||
rv = Arrays.asList(APILocator.getNetManager().wrap(new PacketMWSTile(world, tedesc), true), blockPacket);
|
||||
else
|
||||
rv = Arrays.asList(blockPacket);
|
||||
|
||||
} else if(nUpdatedBlocks < 64 && nUpdateRanges <= updateRanges.length) {
|
||||
PacketMWSMultiBlock mbp = new PacketMWSMultiBlock(this.x, this.z, nUpdatedBlocks, world);
|
||||
rv = new ArrayList<Packet>(8);
|
||||
rv.add(APILocator.getNetManager().wrap(mbp, true));
|
||||
|
||||
//Chunk c = world.getChunkFromChunkCoords(this.x, this.z);
|
||||
|
||||
for(int k = 0; k < nUpdateRanges; k++) {
|
||||
Range r = updateRanges[k];
|
||||
updateRanges[k] = null;
|
||||
|
||||
for(int x_ = r.minx; x_ < r.maxx; x_++)
|
||||
for(int y = r.miny; y < r.maxy; y++)
|
||||
for(int z_ = r.minz; z_ < r.maxz; z_++) {
|
||||
int x = x_ + (this.x << 4);
|
||||
int z = z_ + (this.z << 4);
|
||||
|
||||
mbp.addBlock(x, y, z, world);
|
||||
|
||||
TileEntity te = world.getTileEntity(x, y, z);
|
||||
if(te != null) {
|
||||
Packet teDesc = te.getDescriptionPacket();
|
||||
if(teDesc != null)
|
||||
rv.add(APILocator.getNetManager().wrap(new PacketMWSTile(world, teDesc), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Chunk c = world.getChunkFromChunkCoords(this.x, this.z);
|
||||
rv = new ArrayList<Packet>(16);
|
||||
rv.add(APILocator.getNetManager().wrap(new PacketMWSChunk(this.x, this.z, world, c), true));
|
||||
for(TileEntity te : (Collection<TileEntity>)c.chunkTileEntityMap.values()) {
|
||||
Packet teDesc = te.getDescriptionPacket();
|
||||
if(teDesc != null)
|
||||
rv.add(APILocator.getNetManager().wrap(new PacketMWSTile(world, teDesc), true));
|
||||
}
|
||||
}
|
||||
|
||||
nUpdateRanges = 0;
|
||||
nUpdatedBlocks = 0;
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
private Set<SyncedChunk> changedChunks = new HashSet<SyncedChunk>();
|
||||
private Set<SyncedChunk> allChunks = new HashSet<SyncedChunk>();
|
||||
private LongHashMap chunks = new LongHashMap();
|
||||
|
||||
private SyncedChunk getSyncedChunk(int x, int z, boolean markForUpdate) {
|
||||
long index = ChunkCoordIntPair.chunkXZ2Int(x, z);
|
||||
SyncedChunk s = (SyncedChunk)chunks.getValueByKey(index);
|
||||
if(s == null) {
|
||||
s = new SyncedChunk(x, z);
|
||||
chunks.add(index, s);
|
||||
allChunks.add(s);
|
||||
}
|
||||
if(markForUpdate)
|
||||
synchronized(changedChunks) {
|
||||
changedChunks.add(s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private class WorldListener implements IWorldAccess {
|
||||
|
||||
@Override
|
||||
public void markBlockForUpdate(int var1, int var2, int var3) {
|
||||
getSyncedChunk(var1 >> 4, var3 >> 4, true).addRange(new Range(var1&15, var2, var3&15, var1&15, var2, var3&15));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockForRenderUpdate(int var1, int var2, int var3) {}
|
||||
|
||||
@Override
|
||||
public void markBlockRangeForRenderUpdate(int var1, int var2, int var3,int var4, int var5, int var6) {
|
||||
int mincx = var1 >> 4;
|
||||
int mincz = var3 >> 4;
|
||||
int maxcx = var4 >> 4;
|
||||
int maxcz = var6 >> 4;
|
||||
for(int cx = mincx; cx <= maxcx; cx++) {
|
||||
int minx = (cx == mincx ? var1 & 15 : 0);
|
||||
int maxx = (cx == maxcx ? (var4 & 15) + 1 : 16);
|
||||
for(int cz = mincz; cz <= maxcz; cz++) {
|
||||
int minz = (cz == mincz ? var3 & 15 : 0);
|
||||
int maxz = (cz == maxcz ? (var6 & 15) + 1 : 16);
|
||||
|
||||
getSyncedChunk(cx, cz, true).addRange(new Range(minx, var2, minz, maxx, var5, maxz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(String var1, double var2, double var4, double var6, float var8, float var9) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnParticle(String var1, double var2, double var4, double var6, double var8, double var10, double var12) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCreate(Entity var1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityDestroy(Entity var1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playRecord(String var1, int var2, int var3, int var4) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playAuxSFX(EntityPlayer var1, int var2, int var3, int var4, int var5, int var6) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyBlockPartially(int var1, int var2, int var3, int var4, int var5) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSoundToNearExcept(EntityPlayer var1, String var2, double var3, double var5, double var7, float var9, float var10) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastSound(int var1, int var2, int var3, int var4, int var5) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStaticEntitiesChanged() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*private boolean isInViewingRange(SyncedChunk sc, MWSListener w) {
|
||||
int minx = (sc.x - VIEW_DISTANCE) * 16;
|
||||
int maxx = (sc.x + VIEW_DISTANCE + 1) * 16;
|
||||
int minz = (sc.z - VIEW_DISTANCE) * 16;
|
||||
int maxz = (sc.z + VIEW_DISTANCE + 1) * 16;
|
||||
return w.x >= minx && w.z >= minz && w.x <= maxx && w.z <= maxz;
|
||||
}*/
|
||||
|
||||
private void sendUpdate(SyncedChunk sc) {
|
||||
Collection<Packet> packets = sc.nextUpdatePackets();
|
||||
if(packets == null)
|
||||
return;
|
||||
|
||||
int minx = (sc.x - VIEW_DISTANCE) * 16;
|
||||
int maxx = (sc.x + VIEW_DISTANCE + 1) * 16;
|
||||
int minz = (sc.z - VIEW_DISTANCE) * 16;
|
||||
int maxz = (sc.z + VIEW_DISTANCE + 1) * 16;
|
||||
|
||||
for(MWSListener w : listeners) {
|
||||
if(w.x >= minx && w.x <= maxx && w.z >= minz && w.z <= maxz) {
|
||||
for(Packet p : packets) {
|
||||
w.client.scheduleOutboundPacket(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
for(MWSListener l : new ArrayList<MWSListener>(listeners)) {
|
||||
l.update();
|
||||
if(l.isDead)
|
||||
listeners.remove(l);
|
||||
|
||||
if(l.ticksToNextRangeCheck <= 0) {
|
||||
l.ticksToNextRangeCheck = l.RANGE_CHECK_INTERVAL;
|
||||
updateLoadedChunks(l);
|
||||
} else
|
||||
l.ticksToNextRangeCheck--;
|
||||
}
|
||||
|
||||
synchronized(changedChunks) {
|
||||
if(!changedChunks.isEmpty()) {
|
||||
Collection<SyncedChunk> copy = new ArrayList<SyncedChunk>(changedChunks);
|
||||
changedChunks.clear();
|
||||
for(SyncedChunk sc : copy)
|
||||
sendUpdate(sc);
|
||||
}
|
||||
}
|
||||
|
||||
final int MAX_CHUNKS_PER_TICK = 5;
|
||||
|
||||
int nSent = 0;
|
||||
|
||||
while(sendQueue.size() > 0) {
|
||||
SendQueueEntry e = sendQueue.poll();
|
||||
if(!listeners.contains(e.l))
|
||||
continue;
|
||||
|
||||
//if(SubWorldsMod.sendQueueThrottle(e.l.client))
|
||||
// break;
|
||||
|
||||
//System.out.println("sending "+e.hashCode()+": "+e.cx+","+e.cz+" to "+e.l);
|
||||
|
||||
e.send();
|
||||
nSent++;
|
||||
if(nSent >= MAX_CHUNKS_PER_TICK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SendQueueEntry {
|
||||
public MWSListener l;
|
||||
public int cx, cz;
|
||||
public World world;
|
||||
public Chunk c;
|
||||
|
||||
public SendQueueEntry(MWSListener l, int cx, int cz, World world, Chunk c) {
|
||||
this.c = c;
|
||||
this.cx = cx;
|
||||
this.cz = cz;
|
||||
this.world = world;
|
||||
this.l = l;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void send() {
|
||||
APILocator.getNetManager().send(new PacketMWSChunk(cx, cz, world, c), l.client, true);
|
||||
|
||||
//APILocator.getNetManager().send(new PacketMWSSetWorld(world.provider.dimensionId), l.client, true);
|
||||
for(TileEntity te : (Collection<TileEntity>)c.chunkTileEntityMap.values()) {
|
||||
Packet teDesc = te.getDescriptionPacket();
|
||||
if(teDesc != null)
|
||||
l.client.scheduleOutboundPacket(APILocator.getNetManager().wrap(new PacketMWSTile(world, teDesc), true));
|
||||
//l.client.scheduleOutboundPacket(teDesc);
|
||||
}
|
||||
//APILocator.getNetManager().send(new PacketMWSSetWorld(PacketMWSSetWorld.NORMAL_DIM), l.client, true);
|
||||
}
|
||||
}
|
||||
|
||||
private Queue<SendQueueEntry> sendQueue = new LinkedList<SendQueueEntry>();
|
||||
|
||||
public void addListener(MWSListener l) {
|
||||
World world = worldObj.get();
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
l.update();
|
||||
|
||||
if(l.isDead)
|
||||
return;
|
||||
|
||||
if(!listeners.add(l))
|
||||
return;
|
||||
|
||||
int minx, minz, maxx, maxz;
|
||||
|
||||
if(world.provider instanceof DWWorldProvider) {
|
||||
minx = minz = 0;
|
||||
maxx = ((DWWorldProvider)world.provider).props.xsize >> 4;
|
||||
maxz = ((DWWorldProvider)world.provider).props.zsize >> 4;
|
||||
} else {
|
||||
minx = (l.x>>4) - VIEW_DISTANCE;
|
||||
maxx = (l.x>>4) + VIEW_DISTANCE + 1;
|
||||
minz = (l.z>>4) - VIEW_DISTANCE;
|
||||
maxz = (l.z>>4) + VIEW_DISTANCE + 1;
|
||||
}
|
||||
|
||||
l.client.scheduleOutboundPacket(APILocator.getNetManager().wrap(new PacketMWSBegin(world.provider.dimensionId), true));
|
||||
|
||||
for(int x = minx; x <= maxx; x++)
|
||||
for(int z = minz; z <= maxz; z++) {
|
||||
sendQueue.add(new SendQueueEntry(l, x, z, world, world.getChunkFromChunkCoords(x, z)));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLoadedChunks(MWSListener l) {
|
||||
int minx, minz, maxx, maxz;
|
||||
|
||||
World world = worldObj.get();
|
||||
if(world == null)
|
||||
return;
|
||||
|
||||
if(world.provider instanceof DWWorldProvider) {
|
||||
minx = minz = 0;
|
||||
maxx = ((DWWorldProvider)world.provider).props.xsize >> 4;
|
||||
maxz = ((DWWorldProvider)world.provider).props.zsize >> 4;
|
||||
} else {
|
||||
minx = (l.x>>4) - VIEW_DISTANCE;
|
||||
maxx = (l.x>>4) + VIEW_DISTANCE + 1;
|
||||
minz = (l.z>>4) - VIEW_DISTANCE;
|
||||
maxz = (l.z>>4) + VIEW_DISTANCE + 1;
|
||||
}
|
||||
|
||||
Set<ChunkCoordIntPair> targetChunks = new HashSet<ChunkCoordIntPair>();
|
||||
|
||||
for(int x = minx; x <= maxx; x++)
|
||||
for(int z = minz; z <= maxz; z++) {
|
||||
//System.out.println(l.x+" "+l.z+" "+x+" "+z);
|
||||
targetChunks.add(new ChunkCoordIntPair(x, z));
|
||||
}
|
||||
|
||||
Set<ChunkCoordIntPair> toLoad = new HashSet<ChunkCoordIntPair>(targetChunks);
|
||||
Set<ChunkCoordIntPair> toUnload = new HashSet<ChunkCoordIntPair>(l.loadedChunks);
|
||||
toLoad.removeAll(l.loadedChunks);
|
||||
toUnload.removeAll(targetChunks);
|
||||
|
||||
/*System.out.println("target: "+targetChunks);
|
||||
System.out.println("loaded: "+l.loadedChunks);
|
||||
System.out.println(" load: "+toLoad);
|
||||
System.out.println("unload: "+toUnload);*/
|
||||
|
||||
for(ChunkCoordIntPair ccip : toLoad) {
|
||||
l.loadedChunks.add(ccip);
|
||||
//System.out.println("load "+ccip);
|
||||
sendQueue.add(new SendQueueEntry(l, ccip.chunkXPos, ccip.chunkZPos, world, world.getChunkFromChunkCoords(ccip.chunkXPos, ccip.chunkZPos)));
|
||||
}
|
||||
|
||||
for(ChunkCoordIntPair ccip : toUnload) {
|
||||
l.client.scheduleOutboundPacket(APILocator.getNetManager().wrap(new PacketMWSUnload(world, ccip.chunkXPos, ccip.chunkZPos), true));
|
||||
//System.out.println("unload "+ccip);
|
||||
l.loadedChunks.remove(ccip);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(NetworkManager client) {
|
||||
for(MWSListener l : listeners) {
|
||||
if(l.client == client) {
|
||||
removeListener(l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(MWSListener l) {
|
||||
l.isDead = true;
|
||||
listeners.remove(l);
|
||||
l.client.scheduleOutboundPacket(APILocator.getNetManager().wrap(new PacketMWSEnd(dimensionID), true));
|
||||
}
|
||||
|
||||
void onWorldUnload() {
|
||||
Packet p = APILocator.getNetManager().wrap(new PacketMWSEnd(dimensionID), true);
|
||||
for(MWSListener l : listeners) {
|
||||
l.isDead = true;
|
||||
l.client.scheduleOutboundPacket(p);
|
||||
}
|
||||
listeners.clear();
|
||||
worldObj.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package mods.immibis.subworlds.mws.packets;
|
||||
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class PacketMWSBegin implements /*Runnable,*/ IPacket {
|
||||
|
||||
public int dim;
|
||||
|
||||
public PacketMWSBegin() {}
|
||||
public PacketMWSBegin(int dim) {this.dim = dim;}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return MWSManager.PKT_BEGIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
dim = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onReceived(EntityPlayer source) {
|
||||
/*MainThreadTaskQueue.enqueue(this, Side.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void run() {*/
|
||||
MWSManager.clientBegin(dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return MWSManager.CHANNEL;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package mods.immibis.subworlds.mws.packets;
|
||||
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import mods.immibis.core.MainThreadTaskQueue;
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.world.World;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class PacketMWSBlock implements IPacket, Runnable {
|
||||
|
||||
int x, y, z, type, meta, dim;
|
||||
|
||||
public PacketMWSBlock(int x, int y, int z, World w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.dim = w.provider.dimensionId;
|
||||
this.type = Block.getIdFromBlock(w.getBlock(x, y, z));
|
||||
this.meta = w.getBlockMetadata(x, y, z);
|
||||
}
|
||||
|
||||
public PacketMWSBlock() {}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return MWSManager.PKT_BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(x);
|
||||
out.writeInt(y);
|
||||
out.writeInt(z);
|
||||
out.writeShort((short)type);
|
||||
out.writeByte((byte)meta);
|
||||
out.writeInt(dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
x = in.readInt();
|
||||
y = in.readInt();
|
||||
z = in.readInt();
|
||||
type = in.readShort();
|
||||
meta = in.readByte();
|
||||
dim = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return MWSManager.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onReceived(EntityPlayer source) {
|
||||
MainThreadTaskQueue.enqueue(this, Side.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void run() {
|
||||
World w = MWSManager.getClientWorld(dim);
|
||||
if(w != null) {
|
||||
w.setBlock(x, y, z, Block.getBlockById(type), meta, 3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package mods.immibis.subworlds.mws.packets;
|
||||
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class PacketMWSChunk implements IPacket {
|
||||
|
||||
public int cx, cz, dim;
|
||||
public short[] type;
|
||||
public byte[] meta;
|
||||
public byte[] light;
|
||||
public short mask;
|
||||
|
||||
public PacketMWSChunk(int x, int z, World w, Chunk c) {
|
||||
cx = x;
|
||||
cz = z;
|
||||
dim = w.provider.dimensionId;
|
||||
|
||||
fromChunk(c);
|
||||
}
|
||||
|
||||
public PacketMWSChunk() {}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return MWSManager.PKT_CHUNK;
|
||||
}
|
||||
|
||||
public void fromChunk(Chunk c) {
|
||||
type = new short[16*16*256];
|
||||
meta = new byte[16*16*256];
|
||||
light = new byte[16*16*256];
|
||||
|
||||
mask = 0;
|
||||
for(int k = 0; k < 16; k++)
|
||||
if(c.getBlockStorageArray()[k] != null)
|
||||
mask |= (1 << k);
|
||||
|
||||
int pos = 0;
|
||||
for(int y = 0; y < 256; y++)
|
||||
for(int x = 0; x < 16; x++)
|
||||
for(int z = 0; z < 16; z++, pos++) {
|
||||
type[pos] = (short)Block.getIdFromBlock(c.getBlock(x, y, z));
|
||||
meta[pos] = (byte)c.getBlockMetadata(x, y, z);
|
||||
byte L = (byte)(c.getSavedLightValue(EnumSkyBlock.Block, x, y, z) & 15);
|
||||
byte SL = (byte)(c.getSavedLightValue(EnumSkyBlock.Sky, x, y, z) & 15);
|
||||
light[pos] = (byte)((SL << 4) | L);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void toChunk(Chunk c) {
|
||||
ExtendedBlockStorage[] ebs = c.getBlockStorageArray();
|
||||
|
||||
int pos = 0;
|
||||
for(int y = 0; y < 256; y++) {
|
||||
ExtendedBlockStorage segment = ebs[y >> 4];
|
||||
if((mask & (1 << (y >> 4))) == 0) {
|
||||
pos += 256;
|
||||
ebs[y >> 4] = null;
|
||||
continue;
|
||||
}
|
||||
if(segment == null)
|
||||
segment = ebs[y >> 4] = new ExtendedBlockStorage(y >> 4, true);
|
||||
for(int x = 0; x < 16; x++)
|
||||
for(int z = 0; z < 16; z++, pos++) {
|
||||
int SL = (light[pos] >> 4) & 15;
|
||||
int L = light[pos] & 15;
|
||||
segment.setExtBlocklightValue(x, y&15, z, L);
|
||||
segment.setExtSkylightValue(x, y&15, z, SL);
|
||||
segment.func_150818_a(x, y&15, z, Block.getBlockById(type[pos]));
|
||||
segment.setExtBlockMetadata(x, y&15, z, meta[pos]);
|
||||
}
|
||||
}
|
||||
|
||||
int x = c.xPosition << 4;
|
||||
int z = c.zPosition << 4;
|
||||
|
||||
for(int k = 0; k < 16; k++)
|
||||
if((mask & (1 << k)) != 0)
|
||||
c.worldObj.markBlockRangeForRenderUpdate(x, k << 4, z, x+15, (k<<4)+15, z+15);
|
||||
}
|
||||
|
||||
private static ThreadLocal<byte[]> buffer128kb = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {return new byte[131072];}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(cx);
|
||||
out.writeInt(cz);
|
||||
out.writeInt(dim);
|
||||
out.writeShort(mask);
|
||||
DeflaterOutputStream o = new DeflaterOutputStream(out, new Deflater());
|
||||
//OutputStream o = out;
|
||||
byte[] buffer = buffer128kb.get();
|
||||
int pos = 0;
|
||||
for(short s : type) {
|
||||
buffer[pos++] = (byte)(s >> 8);
|
||||
buffer[pos++] = (byte)s;
|
||||
}
|
||||
o.write(buffer);
|
||||
o.write(meta);
|
||||
o.write(light);
|
||||
o.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
cx = in.readInt();
|
||||
cz = in.readInt();
|
||||
dim = in.readInt();
|
||||
mask = in.readShort();
|
||||
|
||||
InflaterInputStream i = new InflaterInputStream(in);
|
||||
//InputStream i = in;
|
||||
type = new short[65536];
|
||||
meta = new byte[65536];
|
||||
light = new byte[65536];
|
||||
byte[] buffer = buffer128kb.get();
|
||||
int pos = 0;
|
||||
readFully(i, buffer);
|
||||
for(int k = 0; k < 65536; k++, pos += 2) {
|
||||
int b1 = buffer[pos] & 255;
|
||||
int b2 = buffer[pos+1] & 255;
|
||||
//if(b1 == -1 || b2 == -1)
|
||||
// throw new IOException("unexpected EOF");
|
||||
type[k] = (short)((b1 << 8) | b2);
|
||||
}
|
||||
readFully(i, meta);
|
||||
readFully(i, light);
|
||||
}
|
||||
|
||||
private void readFully(InputStream i, byte[] b) throws IOException {
|
||||
int pos = 0;
|
||||
while(pos < b.length) {
|
||||
int read = i.read(b, pos, b.length - pos);
|
||||
if(read < 0)
|
||||
throw new IOException("Unexpected end of stream (after "+pos+" bytes, need "+b.length+")");
|
||||
pos += read;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return MWSManager.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onReceived(EntityPlayer source) {
|
||||
/*MainThreadTaskQueue.enqueue(this, Side.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void run() {*/
|
||||
WorldClient w = MWSManager.getClientWorld(dim);
|
||||
if(w != null) {
|
||||
w.doPreChunk(cx, cz, true);
|
||||
Chunk c = w.getChunkFromChunkCoords(cx, cz);
|
||||
toChunk(c);
|
||||
System.out.println("Received chunk "+dim+"/"+cx+"/"+cz);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package mods.immibis.subworlds.mws.packets;
|
||||
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import mods.immibis.core.MainThreadTaskQueue;
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class PacketMWSEnd implements IPacket, Runnable {
|
||||
|
||||
public int dim;
|
||||
|
||||
public PacketMWSEnd() {}
|
||||
public PacketMWSEnd(int dim) {this.dim = dim;}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return MWSManager.PKT_END;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
dim = in.readInt();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return MWSManager.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onReceived(EntityPlayer source) {
|
||||
MainThreadTaskQueue.enqueue(this, Side.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void run() {
|
||||
MWSManager.clientEnd(dim);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package mods.immibis.subworlds.mws.packets;
|
||||
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import mods.immibis.core.MainThreadTaskQueue;
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.world.World;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class PacketMWSMultiBlock implements IPacket.Asynchronous, Runnable {
|
||||
|
||||
public PacketMWSMultiBlock() {}
|
||||
|
||||
public int size, pos, dim, cx, cz;
|
||||
public byte[] meta;
|
||||
public short[] type;
|
||||
public byte[] x;
|
||||
public int[] y;
|
||||
public byte[] z;
|
||||
|
||||
public PacketMWSMultiBlock(int cx, int cz, int size, World w) {
|
||||
this.size = size;
|
||||
this.cx = cx;
|
||||
this.cz = cz;
|
||||
dim = w.provider.dimensionId;
|
||||
pos = 0;
|
||||
meta = new byte[size];
|
||||
type = new short[size];
|
||||
x = new byte[size];
|
||||
y = new int[size];
|
||||
z = new byte[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return MWSManager.PKT_MULTIBLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(pos);
|
||||
out.writeInt(cx);
|
||||
out.writeInt(cz);
|
||||
out.writeInt(dim);
|
||||
for(int k = 0; k < pos; k++) {
|
||||
out.writeByte(x[k]);
|
||||
out.writeInt(y[k]);
|
||||
out.writeByte(z[k]);
|
||||
out.writeByte(meta[k]);
|
||||
out.writeShort(type[k]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
size = pos = in.readInt();
|
||||
cx = in.readInt();
|
||||
cz = in.readInt();
|
||||
dim = in.readInt();
|
||||
for(int k = 0; k < size; k++) {
|
||||
x[k] = in.readByte();
|
||||
y[k] = in.readInt();
|
||||
z[k] = in.readByte();
|
||||
meta[k] = in.readByte();
|
||||
type[k] = in.readShort();
|
||||
}
|
||||
}
|
||||
|
||||
public void addBlock(int x2, int y2, int z2, World w) {
|
||||
x[pos] = (byte)x2;
|
||||
y[pos] = y2;
|
||||
z[pos] = (byte)z2;
|
||||
type[pos] = (short)Block.getIdFromBlock(w.getBlock(x2 + (cx << 4), y2, z2 + (cz << 4)));
|
||||
meta[pos] = (byte)w.getBlockMetadata(x2 + (cx << 4), y2, z2 + (cz << 4));
|
||||
pos++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return MWSManager.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onReceived(EntityPlayer source) {
|
||||
MainThreadTaskQueue.enqueue(this, Side.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void run() {
|
||||
World w = MWSManager.getClientWorld(dim);
|
||||
if(w != null) {
|
||||
for(int k = 0; k < pos; k++) {
|
||||
w.setBlock((cx<<4) + x[k], y[k], (cz<<4) + z[k], Block.getBlockById(type[k]), meta[k], 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package mods.immibis.subworlds.mws.packets;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
|
||||
public class PacketMWSSetWorld implements IPacket {
|
||||
|
||||
public static final int NORMAL_DIM = Integer.MIN_VALUE;
|
||||
|
||||
public int dim;
|
||||
|
||||
public PacketMWSSetWorld() {}
|
||||
public PacketMWSSetWorld(int dim) {this.dim = dim;}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return MWSManager.PKT_SET_WORLD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
dim = in.readInt();
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
private static WorldClient oldWorld;
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onReceived(EntityPlayer source) {
|
||||
if(dim == NORMAL_DIM) {
|
||||
if(oldWorld == null)
|
||||
throw new AssertionError();
|
||||
Minecraft.getMinecraft().theWorld = oldWorld;
|
||||
oldWorld = null;
|
||||
} else {
|
||||
oldWorld = Minecraft.getMinecraft().theWorld;
|
||||
WorldClient newWorld = MWSManager.getClientWorld(dim);
|
||||
if(newWorld != null)
|
||||
Minecraft.getMinecraft().theWorld = newWorld;
|
||||
else
|
||||
System.out.println("[WARNING] [SubWorlds MWS] Got set-world packet for unknown client world "+dim);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return MWSManager.CHANNEL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package mods.immibis.subworlds.mws.packets;
|
||||
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.network.EnumConnectionState;
|
||||
import net.minecraft.network.INetHandler;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.world.World;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class PacketMWSTile implements IPacket {
|
||||
|
||||
public Packet teDesc;
|
||||
public int dim;
|
||||
public IOException exception;
|
||||
|
||||
public PacketMWSTile() {}
|
||||
|
||||
public PacketMWSTile(World w, Packet teDesc) {
|
||||
this.teDesc = teDesc;
|
||||
dim = w.provider.dimensionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return MWSManager.PKT_TILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
if(exception != null)
|
||||
throw new IOException("delayed wrapped encoding exception", exception);
|
||||
|
||||
Integer packetID = (Integer)EnumConnectionState.PLAY.func_150755_b().inverse().get(teDesc.getClass());
|
||||
if(packetID == null) {
|
||||
//System.out.println("can't send "+teDesc);
|
||||
out.writeByte(0);
|
||||
}
|
||||
else
|
||||
out.writeByte(packetID.intValue());
|
||||
|
||||
out.writeInt(dim);
|
||||
|
||||
if(packetID != null) {
|
||||
PacketBuffer packetbuffer = new PacketBuffer(Unpooled.buffer());
|
||||
teDesc.writePacketData(packetbuffer);
|
||||
|
||||
// TODO waste of memory/garbage
|
||||
byte[] data = new byte[packetbuffer.readableBytes()];
|
||||
packetbuffer.readBytes(data);
|
||||
out.writeInt(data.length);
|
||||
out.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
int packetID = in.readByte() & 255;
|
||||
dim = in.readInt();
|
||||
|
||||
if(packetID == 0)
|
||||
return;
|
||||
|
||||
int len = in.readInt();
|
||||
if(len > 2097152)
|
||||
throw new IOException("input packet size > 2MB");
|
||||
|
||||
// TODO waste of memory/garbage (considering this is coming from a ByteArrayInputStream)
|
||||
byte[] data = new byte[len];
|
||||
in.readFully(data);
|
||||
|
||||
Packet packet;
|
||||
try {
|
||||
packet = ((Class<? extends Packet>)EnumConnectionState.PLAY.func_150755_b().get(packetID)).getConstructor().newInstance();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new IOException("failed to instantiate packet", e);
|
||||
}
|
||||
packet.readPacketData(new PacketBuffer(Unpooled.wrappedBuffer(data)));
|
||||
this.teDesc = packet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return MWSManager.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onReceived(EntityPlayer source) {
|
||||
if(teDesc == null)
|
||||
return;
|
||||
|
||||
WorldClient w = MWSManager.getClientWorld(dim);
|
||||
if(w != null) {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
WorldClient oldWorld = mc.theWorld;
|
||||
|
||||
mc.theWorld = w;
|
||||
|
||||
try {
|
||||
INetHandler handler = Minecraft.getMinecraft().getNetHandler();
|
||||
System.out.println("Received tile packet "+teDesc);
|
||||
teDesc.processPacket(handler);
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
mc.theWorld = oldWorld;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package mods.immibis.subworlds.mws.packets;
|
||||
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import mods.immibis.core.MainThreadTaskQueue;
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.world.World;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class PacketMWSUnload implements IPacket, Runnable {
|
||||
|
||||
public int dim, x, z;
|
||||
|
||||
public PacketMWSUnload() {}
|
||||
public PacketMWSUnload(World world, int x, int z) {this.dim = world.provider.dimensionId; this.x = x; this.z = z;}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return MWSManager.PKT_UNLOAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(dim);
|
||||
out.writeInt(x);
|
||||
out.writeInt(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
dim = in.readInt();
|
||||
x = in.readInt();
|
||||
z = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return MWSManager.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onReceived(EntityPlayer source) {
|
||||
MainThreadTaskQueue.enqueue(this, Side.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void run() {
|
||||
WorldClient w = MWSManager.getClientWorld(dim);
|
||||
if(w != null)
|
||||
w.doPreChunk(x, z, false);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BlockTransparentBedrock extends Block {
|
||||
public BlockTransparentBedrock() {
|
||||
super(Material.rock);
|
||||
|
||||
setBlockUnbreakable();
|
||||
setResistance(6000000.0F);
|
||||
setStepSound(soundTypeStone);
|
||||
setBlockName("tinycarts.transparent_bedrock");
|
||||
disableStats();
|
||||
setBlockTextureName("bedrock");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getUseNeighborBrightness() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) {
|
||||
final float border = 1/16f;
|
||||
return AxisAlignedBB.getBoundingBox((double)par2 + border, (double)par3 + this.minY, (double)par4 + border, (double)par2 + 1-border, (double)par3 + 1-border, (double)par4 + 1-border);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCollidedWithBlock(World par1World, int par2, int par3, int par4, Entity par5Entity) {
|
||||
if(par5Entity instanceof EntityPlayerMP)
|
||||
TinyCartsMod.removeFromCart(par5Entity, false);
|
||||
}
|
||||
|
||||
// render in no passes = invisible
|
||||
@Override
|
||||
public boolean canRenderInPass(int pass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renderAsNormalBlock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void breakBlock(World par1World, int par2, int par3, int par4, Block par5, int par6) {
|
||||
if(allowRemoval.get() > 0)
|
||||
return;
|
||||
|
||||
allowPlacement.incrementAndGet();
|
||||
try {
|
||||
par1World.setBlock(par2, par3, par4, par5);
|
||||
} finally {
|
||||
allowPlacement.decrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockAdded(World par1World, int par2, int par3, int par4) {
|
||||
if(allowPlacement.get() > 0)
|
||||
return;
|
||||
|
||||
allowRemoval.incrementAndGet();
|
||||
try {
|
||||
par1World.setBlockToAir(par2, par3, par4);
|
||||
} finally {
|
||||
allowRemoval.decrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
static AtomicInteger allowPlacement = new AtomicInteger();
|
||||
static AtomicInteger allowRemoval = new AtomicInteger();
|
||||
}
|
271
src/main/java/mods/immibis/tinycarts/CartExternalFakeEntity.java
Normal file
271
src/main/java/mods/immibis/tinycarts/CartExternalFakeEntity.java
Normal file
|
@ -0,0 +1,271 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import mods.immibis.core.api.APILocator;
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.subworlds.ClientFakeEntities;
|
||||
import mods.immibis.subworlds.FakeEntity;
|
||||
import mods.immibis.subworlds.dw.DWEntityRenderer;
|
||||
import mods.immibis.subworlds.dw.DWWorldProvider;
|
||||
import mods.immibis.subworlds.mws.MWSClientWorld;
|
||||
import mods.immibis.subworlds.mws.MWSManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class CartExternalFakeEntity extends FakeEntity {
|
||||
public final int dimID;
|
||||
|
||||
// rotation is applied first when rendering, then translation.
|
||||
// x/y/z is the coordinates of the centre of the player's world in the FE world (not vice versa)
|
||||
public double x, y, z, yaw;
|
||||
//public Quaternion rotation = new Quaternion();
|
||||
|
||||
private double prevX, prevY, prevZ, prevYaw;
|
||||
//private Quaternion prevRotation = rotation.clone();
|
||||
|
||||
public CartExternalFakeEntity(boolean isClient, int dimID) {
|
||||
super(isClient);
|
||||
this.dimID = dimID;
|
||||
}
|
||||
|
||||
public CartExternalFakeEntity(boolean isClient, int entID, int dimID) {
|
||||
super(isClient, entID);
|
||||
this.dimID = dimID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet getUpdatePacket() {
|
||||
final double MOVE_THRESHOLD = 0.2;
|
||||
if(prevYaw == yaw && Math.abs(x - prevX) < MOVE_THRESHOLD && Math.abs(y - prevY) < MOVE_THRESHOLD && Math.abs(z - prevZ) < MOVE_THRESHOLD) {
|
||||
return null;
|
||||
}
|
||||
|
||||
prevYaw = yaw;
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
prevZ = z;
|
||||
|
||||
return APILocator.getNetManager().wrap(new UpdatePacket(this), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet getDescriptionPacket() {
|
||||
return APILocator.getNetManager().wrap(new CreatePacket(this), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet getDestructionPacket() {
|
||||
return APILocator.getNetManager().wrap(new DeletePacket(entityID), true);
|
||||
}
|
||||
|
||||
private boolean updated = false;
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if(isClient) {
|
||||
if(updated)
|
||||
updated = false;
|
||||
else {
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
prevZ = z;
|
||||
prevYaw = yaw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void render(double pl_x, double pl_y, double pl_z, float partialTick) {
|
||||
MWSClientWorld subWorld = MWSManager.getClientWorld(dimID);
|
||||
World plWorld = Minecraft.getMinecraft().theWorld;
|
||||
if(subWorld == null || !(plWorld.provider instanceof DWWorldProvider)) {
|
||||
super.render(pl_x, pl_y, pl_z, partialTick);
|
||||
return;
|
||||
}
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glTranslated(-pl_x, -pl_y, -pl_z);
|
||||
// now 0,0,0 = origin of the world the player is in
|
||||
|
||||
DWWorldProvider pv = (DWWorldProvider)plWorld.provider;
|
||||
GL11.glTranslated(pv.props.xsize/2, 0, pv.props.zsize/2);
|
||||
// now 0,0,0 = centre-bottom of world the player is in
|
||||
|
||||
double cx = prevX + (x - prevX) * partialTick;
|
||||
double cy = prevY + (y - prevY) * partialTick;
|
||||
double cz = prevZ + (z - prevZ) * partialTick;
|
||||
|
||||
// why not just cx,cy,cz?
|
||||
GL11.glTranslated(cx-x, cy-y, cz-z);
|
||||
|
||||
GL11.glScalef(EntityMinecartAwesome.SCALE, EntityMinecartAwesome.SCALE, EntityMinecartAwesome.SCALE);
|
||||
GL11.glRotatef((float)yaw, 0, 1, 0);
|
||||
|
||||
DWEntityRenderer.renderClientWorld(subWorld, partialTick, 0, 0, 0, x, y, z);
|
||||
GL11.glPopMatrix();
|
||||
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
GL11.glColor3f(1, 1, 1);
|
||||
}
|
||||
|
||||
public static class DeletePacket implements IPacket {
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return NetworkHandler.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return NetworkHandler.PKT_CEFE_DELETE;
|
||||
}
|
||||
|
||||
public int entID;
|
||||
|
||||
public DeletePacket() {}
|
||||
public DeletePacket(int id) {entID = id;}
|
||||
|
||||
@Override
|
||||
public void onReceived(EntityPlayer source) {
|
||||
ClientFakeEntities.remove(entID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
entID = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(entID);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CreatePacket implements IPacket {
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return NetworkHandler.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return NetworkHandler.PKT_CEFE_CREATE;
|
||||
}
|
||||
|
||||
public int entID, dimID;
|
||||
public double x, y, z, r;
|
||||
|
||||
public CreatePacket() {}
|
||||
public CreatePacket(CartExternalFakeEntity ent) {
|
||||
entID = ent.entityID;
|
||||
dimID = ent.dimID;
|
||||
x = ent.x;
|
||||
y = ent.y;
|
||||
z = ent.z;
|
||||
r = ent.yaw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceived(EntityPlayer source) {
|
||||
CartExternalFakeEntity e = new CartExternalFakeEntity(true, entID, dimID);
|
||||
e.x = x;
|
||||
e.y = y;
|
||||
e.z = z;
|
||||
e.yaw = r;
|
||||
ClientFakeEntities.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
entID = in.readInt();
|
||||
x = in.readDouble();
|
||||
y = in.readDouble();
|
||||
z = in.readDouble();
|
||||
r = in.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(entID);
|
||||
out.writeDouble(x);
|
||||
out.writeDouble(y);
|
||||
out.writeDouble(z);
|
||||
out.writeDouble(r);
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdatePacket implements IPacket {
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return NetworkHandler.CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getID() {
|
||||
return NetworkHandler.PKT_CEFE_UPDATE;
|
||||
}
|
||||
|
||||
public int entID;
|
||||
public double x, y, z;
|
||||
public float rot;
|
||||
|
||||
public UpdatePacket() {}
|
||||
public UpdatePacket(CartExternalFakeEntity ent) {
|
||||
entID = ent.entityID;
|
||||
x = ent.x;
|
||||
y = ent.y;
|
||||
z = ent.z;
|
||||
rot = (float)ent.yaw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceived(EntityPlayer source) {
|
||||
CartExternalFakeEntity ent = (CartExternalFakeEntity)ClientFakeEntities.get(entID);
|
||||
|
||||
ent.prevX = x;
|
||||
ent.prevY = y;
|
||||
ent.prevZ = z;
|
||||
|
||||
ent.updated = true;
|
||||
|
||||
ent.x = x;
|
||||
ent.y = y;
|
||||
ent.z = z;
|
||||
ent.yaw = rot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
entID = in.readInt();
|
||||
x = in.readDouble();
|
||||
y = in.readDouble();
|
||||
z = in.readDouble();
|
||||
rot = in.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(entID);
|
||||
out.writeDouble(x);
|
||||
out.writeDouble(y);
|
||||
out.writeDouble(z);
|
||||
out.writeFloat(rot);
|
||||
}
|
||||
}
|
||||
}
|
31
src/main/java/mods/immibis/tinycarts/CommandExitCart.java
Normal file
31
src/main/java/mods/immibis/tinycarts/CommandExitCart.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import net.minecraft.command.CommandBase;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
|
||||
public class CommandExitCart extends CommandBase {
|
||||
@Override
|
||||
public boolean canCommandSenderUseCommand(ICommandSender par1iCommandSender) {
|
||||
return par1iCommandSender instanceof EntityPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "exitcart";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandUsage(ICommandSender icommandsender) {
|
||||
return "/exitcart";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processCommand(ICommandSender icommandsender, String[] astring) {
|
||||
if(icommandsender instanceof EntityPlayer)
|
||||
TinyCartsMod.removeFromCart((EntityPlayer)icommandsender, true);
|
||||
else
|
||||
icommandsender.addChatMessage(new ChatComponentText("That command is only applicable to players."));
|
||||
}
|
||||
}
|
340
src/main/java/mods/immibis/tinycarts/EntityMinecartAwesome.java
Normal file
340
src/main/java/mods/immibis/tinycarts/EntityMinecartAwesome.java
Normal file
|
@ -0,0 +1,340 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import mods.immibis.subworlds.FakeEntity;
|
||||
import mods.immibis.subworlds.SubWorldsMod;
|
||||
import mods.immibis.subworlds.dw.DWEntity;
|
||||
import mods.immibis.subworlds.dw.DWManager;
|
||||
import mods.immibis.subworlds.dw.DWWorldProvider;
|
||||
import mods.immibis.subworlds.dw.WorldProps;
|
||||
import net.minecraft.entity.item.EntityMinecart;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.management.ServerConfigurationManager;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.ChunkCoordIntPair;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.ForgeChunkManager;
|
||||
import net.minecraftforge.common.ForgeChunkManager.Ticket;
|
||||
import net.minecraftforge.common.ForgeChunkManager.Type;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.entity.minecart.MinecartInteractEvent;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class EntityMinecartAwesome extends EntityMinecart {
|
||||
|
||||
public static final int XSIZE = 16;
|
||||
public static final int ZSIZE = 10;
|
||||
public static final int YSIZE = 10;
|
||||
|
||||
public static final int SCALE = 10; // render scale; internal blocks per external block
|
||||
|
||||
public EntityMinecartAwesome(World par1World) {
|
||||
super(par1World);
|
||||
}
|
||||
|
||||
public EntityMinecartAwesome(World w, double x, double y, double z) {
|
||||
super(w, x, y, z);
|
||||
if(w.isRemote)
|
||||
throw new IllegalStateException();
|
||||
|
||||
WorldProps props = new WorldProps();
|
||||
props.xsize = XSIZE;
|
||||
props.ysize = YSIZE;
|
||||
props.zsize = ZSIZE;
|
||||
props.generatorClass = InteriorChunkGen.class;
|
||||
internalWorldID = DWManager.createWorld(props);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double getMountedYOffset() {
|
||||
return 0.3f;
|
||||
}
|
||||
|
||||
|
||||
private int internalWorldID;
|
||||
@Override
|
||||
protected void readEntityFromNBT(NBTTagCompound par1nbtTagCompound) {
|
||||
super.readEntityFromNBT(par1nbtTagCompound);
|
||||
internalWorldID = par1nbtTagCompound.getInteger("intwid");
|
||||
}
|
||||
@Override
|
||||
protected void writeEntityToNBT(NBTTagCompound par1nbtTagCompound) {
|
||||
super.writeEntityToNBT(par1nbtTagCompound);
|
||||
par1nbtTagCompound.setInteger("intwid", internalWorldID);
|
||||
}
|
||||
|
||||
private DWSubEntity getDW() {
|
||||
if(riddenByEntity instanceof DWSubEntity)
|
||||
return (DWSubEntity)riddenByEntity;
|
||||
else if(worldObj.isRemote)
|
||||
return null;
|
||||
else {
|
||||
DWSubEntity dwsub = new DWSubEntity(worldObj);
|
||||
dwsub.posX = posX;
|
||||
dwsub.posY = posY;
|
||||
dwsub.posZ = posZ;
|
||||
worldObj.spawnEntityInWorld(dwsub);
|
||||
dwsub.mountEntity(this);
|
||||
return dwsub;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
super.onUpdate();
|
||||
|
||||
getDW();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interactFirst(EntityPlayer par1EntityPlayer)
|
||||
{
|
||||
if(MinecraftForge.EVENT_BUS.post(new MinecartInteractEvent(this, par1EntityPlayer)))
|
||||
return true;
|
||||
|
||||
if(!(par1EntityPlayer instanceof EntityPlayerMP))
|
||||
return false;
|
||||
|
||||
if(worldObj.isRemote)
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
ServerConfigurationManager scm = MinecraftServer.getServer().getConfigurationManager();
|
||||
scm.transferPlayerToDimension((EntityPlayerMP)par1EntityPlayer, internalWorldID, ((DWWorldProvider)getDW().getInternalWorld().provider).teleporter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinecartType() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// XXX the whole purpose of this field is hacky. subworlds should keep track of this for us.
|
||||
static Map<Integer, WeakReference<DWSubEntity>> entitiesByInternalID = new HashMap<Integer, WeakReference<DWSubEntity>>();
|
||||
|
||||
public static class DWSubEntity extends DWEntity {
|
||||
public DWSubEntity(World w) {
|
||||
super(w);
|
||||
setSize(Math.min(XSIZE, ZSIZE)/(float)SCALE, YSIZE/(float)SCALE);
|
||||
}
|
||||
|
||||
public EntityMinecartAwesome getCart() {
|
||||
if(ridingEntity instanceof EntityMinecartAwesome)
|
||||
return (EntityMinecartAwesome)ridingEntity;
|
||||
return null;
|
||||
}
|
||||
|
||||
private int internalWorldID = Integer.MIN_VALUE;
|
||||
|
||||
@Override
|
||||
public void onUnloadOrDestroy() {
|
||||
if(!worldObj.isRemote) {
|
||||
synchronized(entitiesByInternalID) {
|
||||
int intWID = internalWorldID;
|
||||
if(intWID != Integer.MIN_VALUE) {
|
||||
WeakReference<DWSubEntity> ent = entitiesByInternalID.get(intWID);
|
||||
if(ent != null && ent.get() == this) {
|
||||
entitiesByInternalID.remove(intWID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mountEntity(null);
|
||||
super.onUnloadOrDestroy();
|
||||
}
|
||||
|
||||
private Ticket externalTicket, internalTicket;
|
||||
|
||||
private static final int EXTERNAL_VIEW_DISTANCE = 7;
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private void updateChunkLoading() {
|
||||
boolean load = requiresInteriorLoaded();
|
||||
if(load != (externalTicket != null)) {
|
||||
if(DEBUG) System.out.println("[TinyCarts DEBUG] External loading: now "+load);
|
||||
if(load) {
|
||||
WorldServer world = (WorldServer)worldObj;
|
||||
|
||||
externalTicket = ForgeChunkManager.requestTicket(SubWorldsMod.INSTANCE, world, Type.NORMAL);
|
||||
|
||||
int baseX = (int)(posX) >> 4;
|
||||
int baseZ = (int)(posZ) >> 4;
|
||||
|
||||
for(int dx = -EXTERNAL_VIEW_DISTANCE; dx <= EXTERNAL_VIEW_DISTANCE; dx++)
|
||||
for(int dz = -EXTERNAL_VIEW_DISTANCE; dz <= EXTERNAL_VIEW_DISTANCE; dz++) {
|
||||
int x = dx + baseX, z = dz + baseZ;
|
||||
ForgeChunkManager.forceChunk(externalTicket, new ChunkCoordIntPair(x, z));
|
||||
world.theChunkProviderServer.loadChunk(x, z);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ForgeChunkManager.releaseTicket(externalTicket);
|
||||
externalTicket = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(load != (internalTicket != null)) {
|
||||
if(load) {
|
||||
WorldServer world = getInternalWorld();
|
||||
if(world == null)
|
||||
throw new IllegalStateException("Failed to load internal world.");
|
||||
|
||||
internalTicket = ForgeChunkManager.requestTicket(SubWorldsMod.INSTANCE, world, Type.NORMAL);
|
||||
|
||||
int size = (Math.max(XSIZE, YSIZE)+15)/16;
|
||||
|
||||
if(DEBUG) System.out.println("[TinyCarts DEBUG] Internal loading: now true ("+size+"x"+size+")");
|
||||
for(int x = 0; x < size; x++)
|
||||
for(int z = 0; z < size; z++) {
|
||||
ForgeChunkManager.forceChunk(internalTicket, new ChunkCoordIntPair(x, z));
|
||||
world.theChunkProviderServer.loadChunk(x, z);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if(DEBUG) System.out.println("[TinyCarts DEBUG] Internal loading: now false");
|
||||
ForgeChunkManager.releaseTicket(internalTicket);
|
||||
internalTicket = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isDead) { // should always be true
|
||||
int intWID = internalWorldID = getCart().internalWorldID;
|
||||
synchronized(entitiesByInternalID) {
|
||||
WeakReference<DWSubEntity> ref = entitiesByInternalID.get(intWID);
|
||||
DWSubEntity reffed = (ref == null ? null : ref.get());
|
||||
if(reffed == null || (reffed.isDead && reffed != this)) {
|
||||
entitiesByInternalID.put(intWID, new WeakReference<DWSubEntity>(this));
|
||||
}
|
||||
}
|
||||
} else assert false : "updateChunkLoading on dead entity?";
|
||||
}
|
||||
|
||||
private static float getActualClientMinecartYaw(EntityMinecart cart, double old) {
|
||||
double x = cart.posX, y = cart.posY, z = cart.posZ;
|
||||
Vec3 vec3 = cart.func_70489_a(x, y, z);
|
||||
//float f5 = cart.rotationPitch;
|
||||
double d6 = 0.30000001192092896D;
|
||||
float yaw = cart.rotationYaw;
|
||||
|
||||
if (vec3 != null)
|
||||
{
|
||||
Vec3 vec31 = cart.func_70495_a(x, y, z, d6);
|
||||
Vec3 vec32 = cart.func_70495_a(x, y, z, -d6);
|
||||
|
||||
if (vec31 == null)
|
||||
{
|
||||
vec31 = vec3;
|
||||
}
|
||||
|
||||
if (vec32 == null)
|
||||
{
|
||||
vec32 = vec3;
|
||||
}
|
||||
|
||||
//renderX += vec3.xCoord - x;
|
||||
//renderY += (vec31.yCoord + vec32.yCoord) / 2.0D - y;
|
||||
//renderZ += vec3.zCoord - z;
|
||||
Vec3 vec33 = vec32.addVector(-vec31.xCoord, -vec31.yCoord, -vec31.zCoord);
|
||||
|
||||
if (vec33.lengthVector() != 0.0D)
|
||||
{
|
||||
vec33 = vec33.normalize();
|
||||
yaw = (float)(Math.atan2(vec33.zCoord, vec33.xCoord) * 180.0D / Math.PI);
|
||||
//f5 = (float)(Math.atan(vec33.yCoord) * 73.0D);
|
||||
}
|
||||
}
|
||||
|
||||
/*if(Math.abs(angleDiff(old, yaw)) > Math.abs(angleDiff(old, yaw+180)))
|
||||
if(yaw > 0)
|
||||
yaw -= 180;
|
||||
else
|
||||
yaw += 180;*/
|
||||
|
||||
return yaw;
|
||||
}
|
||||
|
||||
/*private static double angleDiff(double a, double b) {
|
||||
b -= a;
|
||||
if(b < 0)
|
||||
b = (b % 360) + 360;
|
||||
b = (b + 180) % 360 - 180;
|
||||
assert !(b < -180 || b > 180) : "angleDiff is broken";
|
||||
return b;
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
if(!worldObj.isRemote && (getCart() == null || getCart().getDW() != this)) {
|
||||
setDead();
|
||||
return;
|
||||
}
|
||||
|
||||
//if(ridingEntity != null && worldObj.isRemote)
|
||||
// System.out.println(worldObj.isRemote+" "+(int)posX+" "+(int)posY+" "+(int)posZ+" "+(int)ridingEntity.posX+" "+(int)ridingEntity.posY+" "+(int)ridingEntity.posZ);
|
||||
|
||||
if(getCart() != null)
|
||||
rotationYaw = !worldObj.isRemote ? ridingEntity.rotationYaw : getActualClientMinecartYaw(getCart(), rotationYaw);
|
||||
//if(worldObj.isRemote) {
|
||||
//System.out.println("yaw "+rotationYaw);
|
||||
//}
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
if(!worldObj.isRemote) {
|
||||
updateChunkLoading();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyGLRotation(float partialTick) {
|
||||
GL11.glScalef(1.0f/SCALE, 1.0f/SCALE, 1.0f/SCALE);
|
||||
if(ridingEntity != null)
|
||||
GL11.glRotatef(-rotationYaw, 0, 1, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FakeEntity createExternalWorldFE() {
|
||||
return new CartExternalFakeEntity(false, getCart().internalWorldID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WorldServer getInternalWorld() {
|
||||
return MinecraftServer.getServer().worldServerForDimension(getCart().internalWorldID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateExternalWorldFE(FakeEntity e_) {
|
||||
CartExternalFakeEntity e = (CartExternalFakeEntity)e_;
|
||||
e.x = posX;
|
||||
e.y = posY;
|
||||
e.z = posZ;
|
||||
e.yaw = ridingEntity == null ? 0 : ridingEntity.rotationYaw;
|
||||
}
|
||||
|
||||
// this is called when a position update is received from the server.
|
||||
// by overriding it we make sure the client doesn't try to be smart and push this entity out of bounding boxes.
|
||||
// also, ignore the position from the update packet. because it's incorrect for entities that are riding other entities.
|
||||
// also, ignore the rotation. because we copy that from the cart entity.
|
||||
// in fact, just do nothing when a position/rotation update is received.
|
||||
@Override
|
||||
public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) {
|
||||
//this.setPosition(par1, par3, par5);
|
||||
//this.setRotation(par7, par8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
120
src/main/java/mods/immibis/tinycarts/InteriorChunkGen.java
Normal file
120
src/main/java/mods/immibis/tinycarts/InteriorChunkGen.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import mods.immibis.subworlds.dw.DWWorldProvider;
|
||||
import mods.immibis.subworlds.dw.WorldProps;
|
||||
import net.minecraft.entity.EnumCreatureType;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.IProgressUpdate;
|
||||
import net.minecraft.world.ChunkPosition;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
|
||||
public class InteriorChunkGen implements IChunkProvider {
|
||||
|
||||
private WorldProps props;
|
||||
private WorldServer w;
|
||||
|
||||
public InteriorChunkGen(WorldServer w, DWWorldProvider wp) {
|
||||
this.props = wp.props;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk provideChunk(int i, int j) {
|
||||
Chunk c = new Chunk(w, i, j);
|
||||
|
||||
BlockTransparentBedrock.allowPlacement.incrementAndGet();
|
||||
|
||||
try {
|
||||
if(i == 0 && j == 0) {
|
||||
for(int x = 0; x < props.xsize; x++)
|
||||
for(int z = 0; z < props.zsize; z++) {
|
||||
c.func_150807_a(x, 0, z, TinyCartsMod.transparentBedrock, 0);
|
||||
c.func_150807_a(x, props.ysize-1, z, TinyCartsMod.transparentBedrock, 0);
|
||||
c.func_150807_a(x, 1, z, Blocks.planks, 0);
|
||||
}
|
||||
|
||||
for(int x = 0; x < props.xsize; x++)
|
||||
for(int y = 0; y < props.ysize; y++) {
|
||||
c.func_150807_a(x, y, 0, TinyCartsMod.transparentBedrock, 0);
|
||||
c.func_150807_a(x, y, props.zsize-1, TinyCartsMod.transparentBedrock, 0);
|
||||
c.func_150807_a(0, y, x, TinyCartsMod.transparentBedrock, 0);
|
||||
c.func_150807_a(props.xsize-1, y, x, TinyCartsMod.transparentBedrock, 0);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
BlockTransparentBedrock.allowPlacement.decrementAndGet();
|
||||
}
|
||||
|
||||
c.generateSkylightMap();
|
||||
Arrays.fill(c.getBiomeArray(), (byte)BiomeGenBase.plains.biomeID);
|
||||
c.isTerrainPopulated = true;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chunkExists(int i, int j) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk loadChunk(int i, int j) {
|
||||
return provideChunk(i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populate(IChunkProvider ichunkprovider, int i, int j) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unloadQueuedChunks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSave() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makeString() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getPossibleCreatures(EnumCreatureType enumcreaturetype, int i, int j, int k) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkPosition func_147416_a(World var1, String var2, int var3, int var4, int var5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoadedChunkCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recreateStructures(int i, int j) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveExtraData() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import mods.immibis.subworlds.dw.DWWorldProvider;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockRailBase;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.item.EntityMinecart;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class ItemMinecartAwesome extends Item {
|
||||
public ItemMinecartAwesome()
|
||||
{
|
||||
this.maxStackSize = 1;
|
||||
|
||||
this.setCreativeTab(CreativeTabs.tabTransport);
|
||||
this.setTextureName("tinycarts:minecart");
|
||||
this.setUnlocalizedName("tinycarts.cart");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10)
|
||||
{
|
||||
if(par3World.provider instanceof DWWorldProvider) {
|
||||
if(par3World.isRemote)
|
||||
par2EntityPlayer.addChatMessage(new ChatComponentText("Don't even think about it."));
|
||||
return false;
|
||||
}
|
||||
|
||||
Block i1 = par3World.getBlock(par4, par5, par6);
|
||||
|
||||
if (BlockRailBase.func_150051_a(i1))
|
||||
{
|
||||
if (!par3World.isRemote)
|
||||
{
|
||||
EntityMinecart entityminecart = new EntityMinecartAwesome(par3World, (double)((float)par4 + 0.5F), (double)((float)par5 + 0.5F), (double)((float)par6 + 0.5F));
|
||||
|
||||
if (par1ItemStack.hasDisplayName())
|
||||
{
|
||||
entityminecart.setMinecartName(par1ItemStack.getDisplayName());
|
||||
}
|
||||
|
||||
par3World.spawnEntityInWorld(entityminecart);
|
||||
}
|
||||
|
||||
--par1ItemStack.stackSize;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
34
src/main/java/mods/immibis/tinycarts/NetworkHandler.java
Normal file
34
src/main/java/mods/immibis/tinycarts/NetworkHandler.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import mods.immibis.core.api.net.IPacket;
|
||||
import mods.immibis.core.api.net.IPacketMap;
|
||||
|
||||
public class NetworkHandler implements IPacketMap {
|
||||
|
||||
public static final String CHANNEL = "TinyCarts";
|
||||
|
||||
public static final byte PKT_CEFE_CREATE = 0;
|
||||
public static final byte PKT_CEFE_DELETE = 1;
|
||||
public static final byte PKT_CEFE_UPDATE = 2;
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket createS2CPacket(byte id) {
|
||||
switch(id) {
|
||||
case PKT_CEFE_CREATE: return new CartExternalFakeEntity.CreatePacket();
|
||||
case PKT_CEFE_DELETE: return new CartExternalFakeEntity.DeletePacket();
|
||||
case PKT_CEFE_UPDATE: return new CartExternalFakeEntity.UpdatePacket();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket createC2SPacket(byte id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import net.minecraft.client.renderer.entity.RenderMinecart;
|
||||
import net.minecraft.entity.item.EntityMinecart;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class RenderMinecartAwesome extends RenderMinecart {
|
||||
private static final ResourceLocation texture = new ResourceLocation("tinycarts", "textures/entity/minecart.png");
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(EntityMinecart par1EntityMinecart) {
|
||||
return texture;
|
||||
}
|
||||
}
|
122
src/main/java/mods/immibis/tinycarts/TinyCartsMod.java
Normal file
122
src/main/java/mods/immibis/tinycarts/TinyCartsMod.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
package mods.immibis.tinycarts;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import mods.immibis.cobaltite.AssignedBlock;
|
||||
import mods.immibis.cobaltite.AssignedItem;
|
||||
import mods.immibis.cobaltite.CobaltiteMod;
|
||||
import mods.immibis.cobaltite.ModBase;
|
||||
import mods.immibis.core.api.APILocator;
|
||||
import mods.immibis.core.api.FMLModInfo;
|
||||
import mods.immibis.subworlds.ExitTeleporter;
|
||||
import mods.immibis.subworlds.dw.DWWorldProvider;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.management.ServerConfigurationManager;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import cpw.mods.fml.client.registry.RenderingRegistry;
|
||||
import cpw.mods.fml.common.Mod;
|
||||
import cpw.mods.fml.common.Mod.EventHandler;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerStartingEvent;
|
||||
import cpw.mods.fml.common.registry.EntityRegistry;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* IMPORTANT SMALL DETAIL: -X EITHER FORWARD OR BACKWARD, -Z IS SIDEWAYS.
|
||||
*/
|
||||
@Mod(modid="TinyCarts", name="TinyCarts", version="0.2", dependencies="required-after:SubWorlds")
|
||||
@CobaltiteMod()
|
||||
@FMLModInfo(authors="immibis", description="", url="")
|
||||
public class TinyCartsMod extends ModBase {
|
||||
@AssignedItem(id="awesomecart")
|
||||
public static ItemMinecartAwesome itemCart;
|
||||
|
||||
@AssignedBlock(id="transparentbedrock")
|
||||
public static BlockTransparentBedrock transparentBedrock;
|
||||
|
||||
@EventHandler
|
||||
public void init(FMLInitializationEvent evt) {
|
||||
EntityRegistry.registerModEntity(EntityMinecartAwesome.class, "tinycarts.cart", 0, this, 50, 1, true);
|
||||
EntityRegistry.registerModEntity(EntityMinecartAwesome.DWSubEntity.class, "tinycarts.cart.dwsub", 1, this, 50, 1, true);
|
||||
|
||||
APILocator.getNetManager().listen(new NetworkHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addRecipes() throws Exception {
|
||||
GameRegistry.addRecipe(new ItemStack(itemCart), "D D", "DDD", 'D', Items.diamond);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerStart(FMLServerStartingEvent evt) {
|
||||
evt.registerServerCommand(new CommandExitCart());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected void clientInit() throws Exception {
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityMinecartAwesome.class, new RenderMinecartAwesome());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void __init(FMLInitializationEvent evt) {super._init(evt);}
|
||||
@EventHandler
|
||||
public void __preinit(FMLPreInitializationEvent evt) {super._preinit(evt);}
|
||||
|
||||
private static long lastRFCWarnTime = 0;
|
||||
public static void removeFromCart(Entity ent, boolean ignoreIfNotInCart) {
|
||||
if(ent.worldObj.isRemote) {
|
||||
assert false : "removeFromCart - on client world!";
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(ent.worldObj.provider instanceof DWWorldProvider)) {
|
||||
assert ignoreIfNotInCart : "removeFromCart - not in DW world!";
|
||||
return;
|
||||
}
|
||||
|
||||
DWWorldProvider wp = (DWWorldProvider)ent.worldObj.provider;
|
||||
if(wp.props.generatorClass != InteriorChunkGen.class) {
|
||||
assert ignoreIfNotInCart : "removeFromCart - not in TinyCart world!";
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX this way of getting the entity is hacky
|
||||
WeakReference<EntityMinecartAwesome.DWSubEntity> dwsub_ref = EntityMinecartAwesome.entitiesByInternalID.get(wp.dimensionId);
|
||||
|
||||
EntityMinecartAwesome.DWSubEntity dwsub = dwsub_ref == null ? null : dwsub_ref.get();
|
||||
if(dwsub == null) {
|
||||
if(lastRFCWarnTime - System.nanoTime() > 5000) {
|
||||
System.out.println("[TinyCarts] Potential problem - entity is leaving a cart, but we can't find the outside of the cart! Entity is "+ent+", internal world ID is "+ent.worldObj.provider.dimensionId+". This message will only be printed once every 5 seconds, maximum.");
|
||||
lastRFCWarnTime = System.nanoTime();
|
||||
}
|
||||
if(ent instanceof EntityPlayer)
|
||||
((EntityPlayer)ent).addChatMessage(new ChatComponentText("Uh oh! Outside of the cart could not be found! Cannot teleport you, sorry."));
|
||||
return;
|
||||
}
|
||||
|
||||
WorldServer outsideWorld = (WorldServer)dwsub.worldObj;
|
||||
double x = dwsub.posX;
|
||||
double y = dwsub.posY;
|
||||
double z = dwsub.posZ;
|
||||
|
||||
x += (outsideWorld.rand.nextDouble() + 1) * (outsideWorld.rand.nextBoolean() ? -1 : 1);
|
||||
z += (outsideWorld.rand.nextDouble() + 1) * (outsideWorld.rand.nextBoolean() ? -1 : 1);
|
||||
|
||||
ServerConfigurationManager scm = MinecraftServer.getServer().getConfigurationManager();
|
||||
if(ent instanceof EntityPlayerMP)
|
||||
scm.transferPlayerToDimension((EntityPlayerMP)ent, outsideWorld.provider.dimensionId, new ExitTeleporter(outsideWorld, x, y, z));
|
||||
//else
|
||||
// scm.transferEntityToWorld(ent, par2, par3WorldServer, par4WorldServer)
|
||||
|
||||
}
|
||||
}
|
2
src/main/resources/assets/tinycarts/lang/en_US.lang
Normal file
2
src/main/resources/assets/tinycarts/lang/en_US.lang
Normal file
|
@ -0,0 +1,2 @@
|
|||
tile.tinycarts.transparent_bedrock.name=You're not supposed to have this block!
|
||||
item.tinycarts.cart.name=Expandable Minecart
|
BIN
src/main/resources/assets/tinycarts/textures/entity/minecart.png
Normal file
BIN
src/main/resources/assets/tinycarts/textures/entity/minecart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
src/main/resources/assets/tinycarts/textures/items/minecart.png
Normal file
BIN
src/main/resources/assets/tinycarts/textures/items/minecart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 354 B |
Loading…
Reference in a new issue