Updated celestial object structure

Replaced group:name with id
Replaced isProvidedByWarpDrive with explicit provider element
Added name, description and custom nbt tag
This commit is contained in:
LemADEC 2017-07-13 11:11:42 +02:00
parent dc08966aff
commit 4f60b3c1b5
10 changed files with 273 additions and 182 deletions

View file

@ -688,11 +688,16 @@ public class WarpDrive implements LoadingCallback {
// only create dimensions if we own them
for (CelestialObject celestialObject : CelestialObjectManager.celestialObjects) {
if (!celestialObject.isVirtual && celestialObject.isProvidedByWarpDrive) {
if (celestialObject.isSpace()) {
if ( !celestialObject.isVirtual
&& !celestialObject.provider.equals(CelestialObject.PROVIDER_OTHER)) {
if ( celestialObject.isSpace()
&& celestialObject.provider.equals(CelestialObject.PROVIDER_SPACE) ) {
DimensionManager.registerDimension(celestialObject.dimensionId, WarpDriveConfig.G_SPACE_PROVIDER_ID);
} else if (celestialObject.isHyperspace()) {
} else if ( celestialObject.isHyperspace()
&& celestialObject.provider.equals(CelestialObject.PROVIDER_HYPERSPACE) ) {
DimensionManager.registerDimension(celestialObject.dimensionId, WarpDriveConfig.G_HYPERSPACE_PROVIDER_ID);
} else {
WarpDrive.logger.error(String.format("Only space and hyperspace dimensions can be provided by WarpDrive. Dimension %d is not what of those.",
celestialObject.dimensionId));
@ -705,12 +710,14 @@ public class WarpDrive implements LoadingCallback {
@EventHandler
public void onFMLPostInitialization(FMLPostInitializationEvent event) {
/* @TODO not sure why it would be needed, disabling for now
// load all owned dimensions at boot
for (CelestialObject celestialObject : CelestialObjectManager.celestialObjects) {
if (celestialObject.isProvidedByWarpDrive) {
if (celestialObject.provider.equals(CelestialObject.PROVIDER_OTHER)) {
DimensionManager.getWorld(celestialObject.dimensionId);
}
}
/**/
WarpDriveConfig.onFMLPostInitialization();

View file

@ -106,7 +106,7 @@ public class TileEntityRadar extends TileEntityAbstractEnergy {
final CelestialObject celestialObject = StarMapRegistry.getCelestialObject(worldObj.provider.dimensionId, xCoord, zCoord);
if (celestialObject != null) {
Vector3 vec3Position = StarMapRegistry.getUniversalCoordinates(celestialObject, xCoord, yCoord, zCoord);
return new Object[] { xCoord, yCoord, zCoord, celestialObject.getFullName(), vec3Position.x, vec3Position.y, vec3Position.z };
return new Object[] { xCoord, yCoord, zCoord, celestialObject.getDisplayName(), vec3Position.x, vec3Position.y, vec3Position.z };
} else {
String name = worldObj.getWorldInfo().getWorldName();
if (name == null || name.isEmpty()) {

View file

@ -92,19 +92,20 @@ public class CommandSpace extends CommandBase {
if (dimensionIdTarget == Integer.MAX_VALUE) {
if (celestialObjectCurrent == null) {
Commons.addChatMessage(commandSender,
String.format("§c/space: player %s is in unknown dimension %d.\cTry specifying an explicit target dimension instead.",
String.format("§c/space: player %s is in unknown dimension %d.\bTry specifying an explicit target dimension instead.",
entityPlayerMP.getCommandSenderName(), entityPlayerMP.worldObj.provider.dimensionId));
continue;
}
if (celestialObjectCurrent.isSpace() || celestialObjectCurrent.isHyperspace()) {
if ( celestialObjectCurrent.isSpace()
|| celestialObjectCurrent.isHyperspace() ) {
// in space or hyperspace => move to closest child
final CelestialObject celestialObjectChild = StarMapRegistry.getClosestChildCelestialObject(entityPlayerMP.worldObj.provider.dimensionId, (int) entityPlayerMP.posX, (int) entityPlayerMP.posZ);
if (celestialObjectChild == null) {
dimensionIdTarget = 0;
} else if (celestialObjectChild.isVirtual) {
Commons.addChatMessage(commandSender,
String.format("§c/space: player %s can't go to %s.\n§cThis is a virtual celestial object. Try specifying an explicit target dimension instead.",
entityPlayerMP.getCommandSenderName(), celestialObjectChild.getFullName()));
String.format("§c/space: player %s can't go to %s.\n§cThis is a virtual celestial object.\n§bTry specifying an explicit target dimension instead.",
entityPlayerMP.getCommandSenderName(), celestialObjectChild.getDisplayName()));
continue;
} else {
dimensionIdTarget = celestialObjectChild.dimensionId;
@ -116,7 +117,8 @@ public class CommandSpace extends CommandBase {
} else {
// on a planet => move to space
final CelestialObject celestialObjectParent = StarMapRegistry.getParentCelestialObject(celestialObjectCurrent);
if (celestialObjectParent == null) {
if ( celestialObjectParent == null
|| celestialObjectParent.isVirtual ) {
dimensionIdTarget = 0;
} else {
@ -138,7 +140,8 @@ public class CommandSpace extends CommandBase {
zTarget -= vEntry.z;
} else {
final CelestialObject celestialObjectChild = StarMapRegistry.getClosestChildCelestialObject(entityPlayerMP.worldObj.provider.dimensionId, (int) entityPlayerMP.posX, (int) entityPlayerMP.posZ);
if (celestialObjectChild != null && celestialObjectChild.dimensionId == dimensionIdTarget) {// moving to child explicitly
if ( celestialObjectChild != null
&& celestialObjectChild.dimensionId == dimensionIdTarget ) {// moving to child explicitly
final VectorI vEntry = celestialObjectChild.getEntryOffset();
xTarget += vEntry.x;
yTarget += vEntry.y;
@ -152,14 +155,14 @@ public class CommandSpace extends CommandBase {
// force to center if we're outside the border
if ( celestialObjectTarget != null
&& celestialObjectTarget.isInsideBorder(xTarget, zTarget) ) {
&& !celestialObjectTarget.isInsideBorder(xTarget, zTarget) ) {
// outside
xTarget = celestialObjectTarget.dimensionCenterX;
zTarget = celestialObjectTarget.dimensionCenterZ;
}
// get target world
WorldServer worldTarget = server.worldServerForDimension(dimensionIdTarget);
final WorldServer worldTarget = server.worldServerForDimension(dimensionIdTarget);
if (worldTarget == null) {
Commons.addChatMessage(commandSender, "§c/space: undefined dimension '" + dimensionIdTarget + "'");
continue;

View file

@ -15,12 +15,12 @@ import net.minecraft.util.AxisAlignedBB;
public class CelestialObjectManager extends XmlFileManager {
private static final CelestialObjectManager INSTANCE = new CelestialObjectManager();
private static HashMap<String, HashMap<String, CelestialObject>> celestialObjectsByGroup = new HashMap<>();
private static HashMap<String, CelestialObject> celestialObjectsById = new HashMap<>();
public static CelestialObject[] celestialObjects = null;
public static void clearForReload() {
// create a new object instead of clearing, in case another thread is iterating through it
celestialObjectsByGroup = new HashMap<>();
celestialObjectsById = new HashMap<>();
}
public static void load(final File dir) {
@ -35,59 +35,53 @@ public class CelestialObjectManager extends XmlFileManager {
}
private void addOrUpdateInRegistry(final CelestialObject celestialObject, final boolean isUpdating) {
final HashMap<String, CelestialObject> celestialObjectByName = celestialObjectsByGroup.computeIfAbsent(celestialObject.group, k -> new HashMap<>());
final CelestialObject celestialObjectExisting = celestialObjectByName.get(celestialObject.name);
final CelestialObject celestialObjectExisting = celestialObjectsById.get(celestialObject.id);
if (celestialObjectExisting == null || isUpdating) {
celestialObjectByName.put(celestialObject.name, celestialObject);
celestialObjectsById.put(celestialObject.id, celestialObject);
} else {
WarpDrive.logger.warn(String.format("Celestial object %s is already defined, keeping original definition", celestialObject.getFullName()));
WarpDrive.logger.warn(String.format("Celestial object %s is already defined, keeping original definition", celestialObject.id));
}
}
private void rebuildAndValidate() {
// optimize execution speed by flattening the data structure
int count = 0;
for(HashMap<String, CelestialObject> mapCelestialObjectByName : celestialObjectsByGroup.values()) {
count += mapCelestialObjectByName.size();
}
final int count = celestialObjectsById.size();
celestialObjects = new CelestialObject[count];
int index = 0;
for(HashMap<String, CelestialObject> mapCelestialObjectByName : celestialObjectsByGroup.values()) {
for (CelestialObject celestialObject : mapCelestialObjectByName.values()) {
celestialObjects[index++] = celestialObject;
celestialObject.resolveParent();
}
for (CelestialObject celestialObject : celestialObjectsById.values()) {
celestialObjects[index++] = celestialObject;
celestialObject.resolveParent();
}
// check overlapping regions
int countErrors = 0;
for (CelestialObject celestialObject1 : celestialObjects) {
for (int indexCelestialObject1 = 0; indexCelestialObject1 < count; indexCelestialObject1++) {
final CelestialObject celestialObject1 = celestialObjects[indexCelestialObject1];
celestialObject1.lateUpdate();
// validate coordinates
if (!celestialObject1.isVirtual) {
if (celestialObject1.parentDimensionId != celestialObject1.dimensionId) {// not hyperspace
final CelestialObject celestialObjectParent = get(celestialObject1.parentGroup, celestialObject1.parentName);
final CelestialObject celestialObjectParent = get(celestialObject1.parentId);
if (celestialObjectParent == null) {
countErrors++;
WarpDrive.logger.error(String.format("Validation error #%d\nCelestial object %s refers to unknown parent %s:%s",
WarpDrive.logger.error(String.format("Validation error #%d\nCelestial object %s refers to unknown parent %s",
countErrors,
celestialObject1.getFullName(),
celestialObject1.parentGroup, celestialObject1.parentName ));
celestialObject1.id,
celestialObject1.parentId ));
} else if ( celestialObject1.parentCenterX - celestialObject1.borderRadiusX < celestialObjectParent.dimensionCenterX - celestialObjectParent.borderRadiusX
|| celestialObject1.parentCenterZ - celestialObject1.borderRadiusZ < celestialObjectParent.dimensionCenterZ - celestialObjectParent.borderRadiusZ
|| celestialObject1.parentCenterX + celestialObject1.borderRadiusX > celestialObjectParent.dimensionCenterX + celestialObjectParent.borderRadiusX
|| celestialObject1.parentCenterZ + celestialObject1.borderRadiusZ > celestialObjectParent.dimensionCenterZ + celestialObjectParent.borderRadiusZ) {
|| celestialObject1.parentCenterZ + celestialObject1.borderRadiusZ > celestialObjectParent.dimensionCenterZ + celestialObjectParent.borderRadiusZ ) {
countErrors++;
WarpDrive.logger.error(String.format("Validation error #%d\nCelestial object %s is outside its parent border.\n%s\n%s\n%s's area in parent %s is outside %s's border %s",
countErrors,
celestialObject1.getFullName(),
celestialObject1.id,
celestialObject1,
celestialObjectParent,
celestialObject1.getFullName(),
celestialObject1.id,
celestialObject1.getAreaInParent(),
celestialObjectParent.getFullName(),
celestialObjectParent.id,
celestialObjectParent.getWorldBorderArea() ));
}
}
@ -98,20 +92,20 @@ public class CelestialObjectManager extends XmlFileManager {
countErrors++;
WarpDrive.logger.error(String.format("Validation error #%d\nCelestial object %s is outside the game border +/-30000000.\n%s\n%s border is %s",
countErrors,
celestialObject1.getFullName(),
celestialObject1.id,
celestialObject1,
celestialObject1.getFullName(),
celestialObject1.id,
celestialObject1.getWorldBorderArea() ));
}
}
// validate against other celestial objects
for (CelestialObject celestialObject2 : celestialObjects) {
if (celestialObject1 == celestialObject2) {
continue;
}
for (int indexCelestialObject2 = indexCelestialObject1 + 1; indexCelestialObject2 < count; indexCelestialObject2++) {
final CelestialObject celestialObject2 = celestialObjects[indexCelestialObject2];
// are they overlapping in a common parent dimension?
if (!celestialObject1.isHyperspace() && !celestialObject2.isHyperspace() && celestialObject1.parentDimensionId == celestialObject2.parentDimensionId) {
if ( !celestialObject1.isHyperspace()
&& !celestialObject2.isHyperspace()
&& celestialObject1.parentDimensionId == celestialObject2.parentDimensionId ) {
final AxisAlignedBB areaInParent1 = celestialObject1.getAreaInParent();
final AxisAlignedBB areaInParent2 = celestialObject2.getAreaInParent();
if (areaInParent1.intersectsWith(areaInParent2)) {
@ -119,8 +113,8 @@ public class CelestialObjectManager extends XmlFileManager {
WarpDrive.logger.error(String.format("Validation error #%d\nOverlapping parent areas detected in dimension %d between %s and %s\nArea1 %s from %s\nArea2 %s from %s",
countErrors,
celestialObject1.parentDimensionId,
celestialObject1.getFullName(),
celestialObject2.getFullName(),
celestialObject1.id,
celestialObject2.id,
areaInParent1,
celestialObject1,
areaInParent2,
@ -128,7 +122,9 @@ public class CelestialObjectManager extends XmlFileManager {
}
}
// are they in the same dimension?
if (!celestialObject1.isVirtual && !celestialObject2.isVirtual && celestialObject1.dimensionId == celestialObject2.dimensionId) {
if ( !celestialObject1.isVirtual
&& !celestialObject2.isVirtual
&& celestialObject1.dimensionId == celestialObject2.dimensionId ) {
final AxisAlignedBB worldBorderArea1 = celestialObject1.getWorldBorderArea();
final AxisAlignedBB worldBorderArea2 = celestialObject2.getWorldBorderArea();
if (worldBorderArea1.intersectsWith(worldBorderArea2)) {
@ -136,8 +132,8 @@ public class CelestialObjectManager extends XmlFileManager {
WarpDrive.logger.error(String.format("Validation error #%d\nOverlapping areas detected in dimension %d between %s and %s\nArea1 %s from %s\nArea2 %s from %s",
countErrors,
celestialObject1.dimensionId,
celestialObject1.getFullName(),
celestialObject2.getFullName(),
celestialObject1.id,
celestialObject2.id,
worldBorderArea1,
celestialObject1,
worldBorderArea2,
@ -160,11 +156,11 @@ public class CelestialObjectManager extends XmlFileManager {
@Override
protected void parseRootElement(final String location, final Element elementCelestialObject) throws InvalidXmlException, SAXException, IOException {
parseCelestiaObjectElement(location, elementCelestialObject, "", "");
parseCelestiaObjectElement(location, elementCelestialObject, "");
}
private void parseCelestiaObjectElement(final String location, final Element elementCelestialObject, final String groupParent, final String nameParent) throws InvalidXmlException, SAXException, IOException {
final CelestialObject celestialObjectRead = new CelestialObject(location, groupParent, nameParent, elementCelestialObject);
private void parseCelestiaObjectElement(final String location, final Element elementCelestialObject, final String parentId) throws InvalidXmlException, SAXException, IOException {
final CelestialObject celestialObjectRead = new CelestialObject(location, parentId, elementCelestialObject);
addOrUpdateInRegistry(celestialObjectRead, false);
@ -173,17 +169,14 @@ public class CelestialObjectManager extends XmlFileManager {
if (!listChildren.isEmpty()) {
for (int indexElement = 0; indexElement < listChildren.size(); indexElement++) {
final Element elementChild = listChildren.get(indexElement);
final String locationChild = String.format("%s Celestial object %s > child %d/%d", location, celestialObjectRead.getFullName(), indexElement + 1, listChildren.size());
parseCelestiaObjectElement(locationChild, elementChild, celestialObjectRead.group, celestialObjectRead.name);
final String locationChild = String.format("%s Celestial object %s > child %d/%d",
location, celestialObjectRead.id, indexElement + 1, listChildren.size());
parseCelestiaObjectElement(locationChild, elementChild, celestialObjectRead.id);
}
}
}
public static CelestialObject get(final String group, final String name) {
final HashMap<String, CelestialObject> celestialObjectByName = celestialObjectsByGroup.get(group);
if (celestialObjectByName == null) {
return null;
}
return celestialObjectByName.get(name);
public static CelestialObject get(final String id) {
return celestialObjectsById.get(id);
}
}

View file

@ -4,11 +4,8 @@ import cr0s.warpdrive.api.IStringSerializable;
import java.util.Random;
/**
* @author Francesco, LemADEC
*
*/
public class StructureGroup implements IStringSerializable {
protected String group;
protected String name;
@ -19,11 +16,7 @@ public class StructureGroup implements IStringSerializable {
@Override
public String getName() {
return name;
}
public String getFullName() {
return group + ":" + name;
return group + ":" + (name.isEmpty() || name.isEmpty() ? "*" : name);
}
public AbstractStructureInstance instantiate(Random random) {
@ -36,4 +29,9 @@ public class StructureGroup implements IStringSerializable {
public String getGroup() {
return group;
}
@Override
public String toString() {
return String.format("StructureGroup %s", getName());
}
}

View file

@ -15,6 +15,8 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.AxisAlignedBB;
@ -34,25 +36,32 @@ public class CelestialObject implements Cloneable, IStringSerializable {
public static final double GRAVITY_LEGACY_SPACE = -1.0D;
public static final double GRAVITY_LEGACY_HYPERSPACE = -2.0D;
public static final double GRAVITY_NORMAL = 1.0D;
public static final String PROVIDER_AUTO = "auto";
public static final String PROVIDER_HYPERSPACE = "WarpDriveHyperspace";
public static final String PROVIDER_SPACE = "WarpDriveSpace";
public static final String PROVIDER_OTHER = "other";
public static final String PROVIDER_NONE = "";
public String group;
public String name;
// unique name so children can refer to parent
public String id;
public String parentGroup;
public String parentName;
public String parentId;
public int parentDimensionId;
public boolean isParentResolved;
public int parentCenterX, parentCenterZ;
public int borderRadiusX, borderRadiusZ;
public String displayName;
public String description;
public NBTTagCompound nbtTagCompound;
public boolean isVirtual;
public int dimensionId;
public int dimensionCenterX, dimensionCenterZ;
public double gravity;
public boolean isBreathable;
public boolean isProvidedByWarpDrive;
private boolean isProvidedByWarpDrive_defined = false;
public String provider;
private final RandomCollection<StructureGroup> randomStructures = new RandomCollection<>();
@ -65,8 +74,8 @@ public class CelestialObject implements Cloneable, IStringSerializable {
public LinkedHashSet<RenderData> setRenderData;
public CelestialObject(final String location, final String parentElementGroup, final String parentElementName, Element elementCelestialObject) throws InvalidXmlException {
loadFromXmlElement(location, parentElementGroup, parentElementName, elementCelestialObject);
public CelestialObject(final String location, final String parentId, Element elementCelestialObject) throws InvalidXmlException {
loadFromXmlElement(location, parentId, elementCelestialObject);
}
public CelestialObject(final int parDimensionId, final int parDimensionCenterX, final int parDimensionCenterZ,
@ -90,81 +99,117 @@ public class CelestialObject implements Cloneable, IStringSerializable {
@Override
public String getName() {
return name;
return id;
}
public String getFullName() {
return String.format("%s:%s", group, name);
public String getDisplayName() {
return displayName;
}
public boolean loadFromXmlElement(final String location, final String parentElementGroup, final String parentElementName, final Element elementCelestialObject) throws InvalidXmlException {
public boolean loadFromXmlElement(final String location, final String parentElementId, final Element elementCelestialObject) throws InvalidXmlException {
// get identity
group = elementCelestialObject.getAttribute("group");
if (group.isEmpty()) {
throw new InvalidXmlException(String.format("Celestial object %s is missing a group attribute!", location));
id = elementCelestialObject.getAttribute("id");
if (id.isEmpty()) {
throw new InvalidXmlException(String.format("Celestial object %s is missing an id attribute!", location));
}
name = elementCelestialObject.getAttribute("name");
if (name.isEmpty()) {
throw new InvalidXmlException(String.format("Celestial object %s is missing a name attribute!", location));
}
WarpDrive.logger.info("- found Celestial object " + getFullName());
WarpDrive.logger.info("- found Celestial object " + id);
// get optional parent element, defaulting to parent defined by element hierarchy
parentGroup = parentElementGroup;
parentName = parentElementName;
parentId = parentElementId;
final List<Element> listParents = XmlFileManager.getChildrenElementByTagName(elementCelestialObject,"parent");
if (listParents.size() > 1) {
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one parent element", getFullName()));
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one parent element", id));
}
if (listParents.size() == 1) {
final Element elementParent = listParents.get(0);
// save linked parent
final String parentGroupRead = elementParent.getAttribute("group");
final String parentNameRead = elementParent.getAttribute("name");
if (!parentNameRead.isEmpty()) {
parentName = parentNameRead;
if (!parentGroupRead.isEmpty()) {
parentGroup = parentGroupRead;
}
} else if (!parentGroupRead.isEmpty()) {
throw new InvalidXmlException(String.format("Celestial object %s parent can't have a group without a name", getFullName()));
final String parentIdRead = elementParent.getAttribute("id");
if (!parentIdRead.isEmpty()) {
parentId = parentIdRead;
}
// get required center element
final List<Element> listCenters = XmlFileManager.getChildrenElementByTagName(elementParent, "center");
if (listCenters.size() != 1) {
throw new InvalidXmlException(String.format("Celestial object %s parent requires exactly one center element", getFullName()));
final List<Element> listElements = XmlFileManager.getChildrenElementByTagName(elementParent, "center");
if (listElements.size() != 1) {
throw new InvalidXmlException(String.format("Celestial object %s parent requires exactly one center element", id));
}
final Element elementCenter = listCenters.get(0);
final Element elementCenter = listElements.get(0);
parentCenterX = Integer.parseInt(elementCenter.getAttribute("x"));
parentCenterZ = Integer.parseInt(elementCenter.getAttribute("z"));
}
// get required size element
{
final List<Element> listSizes = XmlFileManager.getChildrenElementByTagName(elementCelestialObject, "size");
if (listSizes.size() != 1) {
throw new InvalidXmlException(String.format("Celestial object %s requires exactly one size element", getFullName()));
final List<Element> listElements = XmlFileManager.getChildrenElementByTagName(elementCelestialObject, "size");
if (listElements.size() != 1) {
throw new InvalidXmlException(String.format("Celestial object %s requires exactly one size element", id));
}
final Element elementSize = listSizes.get(0);
final Element elementSize = listElements.get(0);
borderRadiusX = Integer.parseInt(elementSize.getAttribute("x")) / 2;
borderRadiusZ = Integer.parseInt(elementSize.getAttribute("z")) / 2;
}
// get optional name elements
{
final List<Element> listElements = XmlFileManager.getChildrenElementByTagName(elementCelestialObject, "name");
if (listElements.size() > 1) {
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one name element", id));
}
if (listElements.size() == 1) {
final Element elementName = listElements.get(0);
displayName = elementName.getNodeValue();
} else {
displayName = id;
}
}
// get optional description element
{
final List<Element> listElements = XmlFileManager.getChildrenElementByTagName(elementCelestialObject, "description");
if (listElements.size() > 1) {
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one description element", id));
}
if (listElements.size() == 1) {
final Element elementName = listElements.get(0);
description = elementName.getNodeValue();
} else {
description = "";
}
}
// get optional NBT element
{
final List<Element> listElements = XmlFileManager.getChildrenElementByTagName(elementCelestialObject, "nbt");
if (listElements.size() > 1) {
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one nbt element", id));
}
nbtTagCompound = null;
if (listElements.size() == 1) {
final Element elementName = listElements.get(0);
final String stringNBT = elementName.getNodeValue();
if (!stringNBT.isEmpty()) {
try {
nbtTagCompound = (NBTTagCompound) JsonToNBT.func_150315_a(stringNBT);
} catch (NBTException exception) {
throw new InvalidXmlException(String.format("Invalid nbt for Celestial object %s", id));
}
}
}
}
// get optional dimension element
final List<Element> listDimensions = XmlFileManager.getChildrenElementByTagName(elementCelestialObject, "dimension");
if (listDimensions.size() > 1) {
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one dimension element", getFullName()));
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one dimension element", id));
}
if (listDimensions.size() == 0) {
isVirtual = true;
dimensionId = 0;
gravity = GRAVITY_NORMAL;
isBreathable = true;
isProvidedByWarpDrive = false;
provider = PROVIDER_NONE;
dimensionCenterX = 0;
dimensionCenterZ = 0;
} else {
@ -174,40 +219,46 @@ public class CelestialObject implements Cloneable, IStringSerializable {
dimensionId = Integer.parseInt(elementDimension.getAttribute("id"));
gravity = parseGravity(elementDimension.getAttribute("gravity"));
isBreathable = Boolean.parseBoolean(elementDimension.getAttribute("isBreathable"));
if (elementDimension.hasAttribute("isProvidedByWarpDrive")) {
isProvidedByWarpDrive = Boolean.parseBoolean(elementDimension.getAttribute("isProvidedByWarpDrive"));
isProvidedByWarpDrive_defined = true;
} else {
isProvidedByWarpDrive_defined = false;
// get optional provider element
{
final List<Element> listElements = XmlFileManager.getChildrenElementByTagName(elementDimension, "provider");
if (listElements.size() > 1) {
throw new InvalidXmlException(String.format("Celestial object %s dimension can only have up to one provider element", id));
}
if (listElements.size() == 1) {
final Element element = listElements.get(0);
provider = element.getAttribute("type");
} else {
provider = PROVIDER_AUTO;
}
}
// get required center element
final List<Element> listCenters = XmlFileManager.getChildrenElementByTagName(elementDimension, "center");
if (listCenters.size() != 1) {
throw new InvalidXmlException( String.format("Celestial object %s dimension requires exactly one center element", getFullName()));
throw new InvalidXmlException(String.format("Celestial object %s dimension requires exactly one center element", id));
}
final Element elementCenter = listCenters.get(0);
dimensionCenterX = Integer.parseInt(elementCenter.getAttribute("x"));
dimensionCenterZ = Integer.parseInt(elementCenter.getAttribute("z"));
// get optional generate element(s)
final List<Element> listGenerates = XmlFileManager.getChildrenElementByTagName(elementCelestialObject, "generate");
final List<Element> listGenerates = XmlFileManager.getChildrenElementByTagName(elementDimension, "generate");
for (int indexElement = 0; indexElement < listGenerates.size(); indexElement++) {
final Element elementGenerate = listGenerates.get(indexElement);
final String locationGenerate = String.format("Celestial object %s generate %d/%d", getFullName(), indexElement + 1, listGenerates.size());
final String locationGenerate = String.format("Celestial object %s generate %d/%d", id, indexElement + 1, listGenerates.size());
parseGenerateElement(locationGenerate, elementGenerate);
}
// get optional effect element(s)
// @TODO not implemented
WarpDrive.logger.info(" loaded " + this);
}
// get optional skybox element
final List<Element> listSkyboxes = XmlFileManager.getChildrenElementByTagName(elementCelestialObject, "skybox");
if (listSkyboxes.size() > 1) {
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one skybox element", getFullName()));
throw new InvalidXmlException(String.format("Celestial object %s can only have up to one skybox element", id));
}
if (listSkyboxes.isEmpty()) {
backgroundColor = new ColorData(0.0F , 0.0F , 0.0F );
@ -218,7 +269,7 @@ public class CelestialObject implements Cloneable, IStringSerializable {
factorFog = new ColorData(0.94F , 0.94F , 0.91F);
} else {
final Element elementSkybox = listSkyboxes.get(0);
final String locationSkybox = String.format("Celestial object %s skybox 1/1", getFullName());
final String locationSkybox = String.format("Celestial object %s skybox 1/1", id);
backgroundColor = getColorData(locationSkybox, elementSkybox, "backgroundColor" , 0.0F, 0.0F, 0.0F );
baseStarBrightness = getFloat(locationSkybox, elementSkybox, "starBrightnessBase", 0.0F);
vanillaStarBrightness = getFloat(locationSkybox, elementSkybox, "starBrightnessVanilla", 1.0F);
@ -233,12 +284,16 @@ public class CelestialObject implements Cloneable, IStringSerializable {
if (!listRenders.isEmpty()) {
for (int indexElement = 0; indexElement < listRenders.size(); indexElement++) {
final Element elementRender = listRenders.get(indexElement);
final String locationRender = String.format("Celestial object %s render %d/%d", getFullName(), indexElement + 1, listRenders.size());
final String locationRender = String.format("Celestial object %s render %d/%d", id, indexElement + 1, listRenders.size());
final RenderData renderData = new RenderData(locationRender, elementRender);
setRenderData.add(renderData);
}
}
if (WarpDriveConfig.LOGGING_WORLD_GENERATION) {
WarpDrive.logger.info(" loaded " + this);
}
return true;
}
@ -313,20 +368,27 @@ public class CelestialObject implements Cloneable, IStringSerializable {
public void resolveParent() {
// is it an hyperspace/top level dimension?
if (parentGroup.isEmpty() && parentName.isEmpty()) {
if (parentId.isEmpty()) {
parentDimensionId = dimensionId;
} else {
final CelestialObject celestialObjectParent = CelestialObjectManager.get(parentGroup, parentName);
final CelestialObject celestialObjectParent = CelestialObjectManager.get(parentId);
if (celestialObjectParent != null) {
parentDimensionId = celestialObjectParent.dimensionId;
}
// (failure will be detected during validation)
}
isParentResolved = true;
}
public void lateUpdate() {
if (!isProvidedByWarpDrive_defined) {
isProvidedByWarpDrive = isHyperspace() || isSpace();
if (provider.equals(PROVIDER_AUTO)) {
if (isHyperspace()) {
provider = PROVIDER_HYPERSPACE;
} else if (isSpace()) {
provider = PROVIDER_SPACE;
} else {
provider = PROVIDER_OTHER;
}
}
}
@ -461,11 +523,9 @@ public class CelestialObject implements Cloneable, IStringSerializable {
public void readFromNBT(NBTTagCompound nbtTagCompound) {
isParentResolved = false;
group = nbtTagCompound.getString("group");
name = nbtTagCompound.getString("name");
id = nbtTagCompound.getString("id");
parentGroup = nbtTagCompound.getString("parentGroup");
parentName = nbtTagCompound.getString("parentName");
parentId = nbtTagCompound.getString("parentId");
parentCenterX = nbtTagCompound.getInteger("parentCenterX");
parentCenterZ = nbtTagCompound.getInteger("parentCenterZ");
@ -479,16 +539,14 @@ public class CelestialObject implements Cloneable, IStringSerializable {
dimensionCenterZ = 0;
gravity = GRAVITY_NORMAL;
isBreathable = true;
isProvidedByWarpDrive = false;
isProvidedByWarpDrive_defined = false;
provider = PROVIDER_NONE;
} else {
dimensionId = nbtTagCompound.getInteger("dimensionId");
dimensionCenterX = nbtTagCompound.getInteger("dimensionCenterX");
dimensionCenterZ = nbtTagCompound.getInteger("dimensionCenterZ");
gravity = nbtTagCompound.getDouble("gravity");
isBreathable = nbtTagCompound.getBoolean("isBreathable");
isProvidedByWarpDrive = nbtTagCompound.getBoolean("isProvidedByWarpDrive");
isProvidedByWarpDrive_defined = true;
provider = nbtTagCompound.getString("provider");
}
// randomStructures are server side only
@ -510,11 +568,9 @@ public class CelestialObject implements Cloneable, IStringSerializable {
}
public void writeToNBT(NBTTagCompound nbtTagCompound) {
nbtTagCompound.setString("group", group);
nbtTagCompound.setString("name", name);
nbtTagCompound.setString("id", id);
nbtTagCompound.setString("parentGroup", parentGroup);
nbtTagCompound.setString("parentName", parentName);
nbtTagCompound.setString("parentId", parentId);
nbtTagCompound.setInteger("parentCenterX", parentCenterX);
nbtTagCompound.setInteger("parentCenterZ", parentCenterZ);
@ -522,20 +578,13 @@ public class CelestialObject implements Cloneable, IStringSerializable {
nbtTagCompound.setInteger("borderRadiusZ", borderRadiusZ);
nbtTagCompound.setBoolean("isVirtual", isVirtual);
if (isVirtual) {
dimensionId = 0;
dimensionCenterX = 0;
dimensionCenterZ = 0;
gravity = GRAVITY_NORMAL;
isBreathable = true;
isProvidedByWarpDrive = false;
} else {
if (!isVirtual) {
nbtTagCompound.setInteger("dimensionId", dimensionId);
nbtTagCompound.setInteger("dimensionCenterX", dimensionCenterX);
nbtTagCompound.setInteger("dimensionCenterZ", dimensionCenterZ);
nbtTagCompound.setDouble("gravity", gravity);
nbtTagCompound.setBoolean("isBreathable", isBreathable);
nbtTagCompound.setBoolean("isProvidedByWarpDrive", isProvidedByWarpDrive);
nbtTagCompound.setString("provider", provider);
}
// randomStructures are server side only
@ -583,20 +632,20 @@ public class CelestialObject implements Cloneable, IStringSerializable {
stringParent = String.format("Parent(%d @ %d %d)",
parentDimensionId, parentCenterX, parentCenterZ);
} else {
stringParent = String.format("Parent(%s:%s @ %d %d)",
parentGroup, parentName, parentCenterX, parentCenterZ);
stringParent = String.format("Parent(%s @ %d %d)",
parentId, parentCenterX, parentCenterZ);
}
if (isVirtual) {
return String.format("CelestialObject %s:%s [-Virtual- Border(%d %d) %s]",
group, name,
return String.format("CelestialObject %s [-Virtual- Border(%d %d) %s]",
id,
2 * borderRadiusX, 2 * borderRadiusZ,
stringParent);
} else {
return String.format("CelestialObject %s:%s [Dimension %d @ %d %d Border(%d %d) %s isProvidedByWarpDrive %s gravity %.3f isBreathable %s]",
group, name, dimensionId, dimensionCenterX, dimensionCenterZ,
return String.format("CelestialObject %s [Dimension %d @ %d %d Border(%d %d) %s provider %s gravity %.3f isBreathable %s]",
id, dimensionId, dimensionCenterX, dimensionCenterZ,
2 * borderRadiusX, 2 * borderRadiusZ,
stringParent,
isProvidedByWarpDrive, gravity, isBreathable);
provider, gravity, isBreathable);
}
}

View file

@ -112,8 +112,8 @@ public class StarMapRegistry {
}
}
public static CelestialObject getCelestialObject(final String group, final String name) {
return CelestialObjectManager.get(group, name);
public static CelestialObject getCelestialObject(final String id) {
return CelestialObjectManager.get(id);
}
public static CelestialObject getCelestialObject(final World world, final int x, final int z) {
@ -124,7 +124,8 @@ public class StarMapRegistry {
double distanceClosest = Double.POSITIVE_INFINITY;
CelestialObject celestialObjectClosest = null;
for (final CelestialObject celestialObject : CelestialObjectManager.celestialObjects) {
if (dimensionId == celestialObject.dimensionId) {
if ( !celestialObject.isVirtual
&& dimensionId == celestialObject.dimensionId ) {
final double distanceSquared = celestialObject.getSquareDistanceOutsideBorder(x, z);
if (distanceSquared <= 0) {
return celestialObject;
@ -143,7 +144,7 @@ public class StarMapRegistry {
}
public static CelestialObject getParentCelestialObject(final CelestialObject celestialObject ) {
return getCelestialObject(celestialObject.parentGroup, celestialObject.parentName);
return getCelestialObject(celestialObject.parentId);
}
public static CelestialObject getClosestChildCelestialObject(final int dimensionId, final int x, final int z) {
@ -308,6 +309,9 @@ public class StarMapRegistry {
vec3Result.y -= 256.0D;
vec3Result.z -= vEntry.z;
celestialObjectNode = StarMapRegistry.getCelestialObject(celestialObjectNode.parentDimensionId, celestialObjectNode.parentCenterX, celestialObjectNode.parentCenterZ);
if (celestialObjectNode == null) {
return null;
}
}
return vec3Result;
}

View file

@ -180,12 +180,15 @@ public class RenderSpaceSky extends IRenderHandler {
/**/
// Planets
if (celestialObject != null) {
if (celestialObject != null && celestialObject.opacityCelestialObjects > 0.0F) {
final Vector3 vectorPlayer = StarMapRegistry.getUniversalCoordinates(celestialObject, vec3Player.xCoord, vec3Player.yCoord, vec3Player.zCoord);
for (CelestialObject celestialObjectChild : CelestialObjectManager.celestialObjects) {
if (celestialObject == celestialObjectChild) {
continue;
}
if (!celestialObject.id.equals(celestialObjectChild.parentId)) {
continue;
}
renderCelestialObject(tessellator,
celestialObjectChild,
celestialObject.opacityCelestialObjects,
@ -260,9 +263,6 @@ public class RenderSpaceSky extends IRenderHandler {
private static void renderCelestialObject(final Tessellator tessellator, final CelestialObject celestialObject,
final float alphaSky, final Vector3 vectorPlayer) {
// @TODO compute relative coordinates for rendering on celestialObject
if (celestialObject.isHyperspace() || celestialObject.isSpace()) {
return;
}
// get universal coordinates
final Vector3 vectorCenter = StarMapRegistry.getUniversalCoordinates(celestialObject,
@ -273,6 +273,9 @@ public class RenderSpaceSky extends IRenderHandler {
celestialObject.dimensionCenterX + celestialObject.borderRadiusX,
64,
celestialObject.dimensionCenterZ + celestialObject.borderRadiusZ);
if (vectorCenter == null || vectorBorderPos == null) {// probably an invalid celestial object tree
return;
}
final double borderRadiusX = vectorBorderPos.x - vectorCenter.x;
final double borderRadiusZ = vectorBorderPos.z - vectorCenter.z;
@ -312,7 +315,7 @@ public class RenderSpaceSky extends IRenderHandler {
final double offsetZ = (1.0 - transitionOrbit) * (distanceToCenterZ / borderRadiusZ);
// simulating a non-planar universe...
final double planetY_far = (celestialObject.dimensionId + 99 % 100 - 50) * Math.log(distanceToCenter) / 4.0D;
final double planetY_far = (celestialObject.dimensionId + 99 % 100 - 50) * Math.log(distanceToCenter) / 1.0D;
final double planetY = planetY_far * transitionApproaching;
// render range is only used for Z-ordering

View file

@ -148,7 +148,7 @@
<xs:sequence>
<xs:element name="center" type="wd:elementPosition" minOccurs="1" maxOccurs="1" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="optional" />
<xs:attribute name="id" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
@ -159,6 +159,11 @@
</xs:complexType>
</xs:element>
<xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="nbt" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="dimension" type="wd:elementDimension" minOccurs="0" maxOccurs="1" />
<xs:element name="skybox" minOccurs="0" maxOccurs="1">
@ -187,8 +192,7 @@
</xs:choice>
</xs:sequence>
<xs:attribute name="group" type="xs:string" use="required" />
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="id" type="xs:string" use="required" />
<xs:attribute name="mods" type="xs:string" use="optional" />
</xs:complexType>
@ -200,12 +204,29 @@
</xs:annotation>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="center" type="wd:elementPosition" minOccurs="1" maxOccurs="1" />
<xs:element name="provider" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="type" use="required">
<xs:simpleType>
<xs:union memberTypes="xs:double">
<xs:simpleType>
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="auto" />
<xs:enumeration value="WarpDriveSpace" />
<xs:enumeration value="WarpDriveHyperspace" />
<xs:enumeration value="other" />
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="generate" type="wd:elementGenerate" minOccurs="0" maxOccurs="unbounded" />
<!-- <xs:element name="effects" type="wd:effectElement" minOccurs="0" maxOccurs="unbounded" /> @TODO Not implemented -->
</xs:sequence>
<xs:attribute name="id" type="xs:int" use="required" />
<xs:attribute name="isProvidedByWarpDrive" type="xs:boolean" use="optional" default="false" />
<xs:attribute name="isBreathable" type="xs:boolean" use="required" />
<xs:attribute name="gravity" use="required">
<xs:simpleType>

View file

@ -9,17 +9,25 @@
They can be a planet, a more abstract construct like solar system (space dimension) or the all mighty hyperspace.
Hyperspace is a dimension which is its own parent. In other words, hyperspace.dimensionId = hyperspace.parentDimensionId.
Space is a dimension with Hyperspace as its parent.
In theory, multiple planets can exists in the same minecraft world.
In theory, multiple planets can exists in the same minecraft world (for example: The Twilight Forest exist on multiple planets in different star systems).
In theory, multiple hyperspaces can be defined.
celestialObject.id should be unique for each Celestial object.
-->
<!-- Top level is hyperspace, typically a galaxy. -->
<celestialObject group="milkyWay" name="hyperspace">
<celestialObject id="hyperspace">
<!--
size defines the world border size, measured in blocks. This is also the size of the orbit area in space, so don't go too big.
name defines an optional display name for the player HUD. It defaults to the celestialObject's id.
description defines an optional text displayed on the player HUD.
name and description support colors with § or & as the escape code. '\n' is also supported.
nbt defines a JSON string for custom tags. It's used by WarpDrive extensions.
-->
<size x="400000" z="400000" />
<name>§lHyperspace</name>
<description>Your ship warp bubble is your\nonly protection.</description>
<!--
dimension defines an actual game world. If it's missing, that celestialObject remains visible but you can't "land" on it.
@ -27,11 +35,15 @@
dimension.isBreathable: this is a boolean flag defining if ambient atmosphere is breathable.
dimension.gravity: this is the gravity simulation type. Valid keywords are none (0.0), legacySpace, legacyHyperspace, normal (1.0).
dimension.center.x, dimension.center.z: those are the center coordinate of that dimension world border, measured in blocks. For convenience, it's usually 0, 0.
dimension.isProvidedByWarpDrive (optional): this is a boolean flag defining if WarpDrive provides this dimension or not.
Currently only Space and Hyperspace can be provided: use other mods to generate planet world.
-->
<dimension id="-3" isBreathable="false" gravity="legacyHyperspace" isProvidedByWarpDrive="true">
<dimension id="-3" isBreathable="false" gravity="legacyHyperspace">
<center x="0" z="0" />
<!--
provider defines how the world biomes are generated. If it's missing, the mod tries to self-assign space and hyperspace dimensions.
provider.type: this is the provider type. Valid keywords are "auto", "WarpDriveSpace", "WarpDriveHyperspace", "other".
Currently only Space and Hyperspace can be provided: use other mods to generate planet world.
-->
<provider type="WarpDriveHyperspace" />
</dimension>
<!--
@ -54,7 +66,7 @@
</skybox>
<!-- Second level is space, typically a star system. -->
<celestialObject group="milkyWay" name="solarSystem">
<celestialObject id="solarSystem">
<!--
parent defines the relation with a bigger enveloping celestial object.
parent.group, parent.name (optional): when using multiple files, you can attach to a parent by its group and name.
@ -64,8 +76,9 @@
<center x="50000" z="10000" />
</parent>
<size x="200000" z="200000" />
<dimension id="-2" isBreathable="false" gravity="legacySpace" isProvidedByWarpDrive="true">
<dimension id="-2" isBreathable="false" gravity="legacySpace">
<center x="0" z="0" />
<provider type="WarpDriveSpace" />
<!--
generate defines the chance of different structures to generate
generate.group, generate.name: identify the structure from the related XML files
@ -86,7 +99,7 @@
</skybox>
<!-- Sun is just displayed, there's no actual game dimension -->
<celestialObject group="solarSystem" name="sun">
<celestialObject id="sun">
<parent>
<!-- sun is at the center of the solarSystem -->
<center x="0" z="0" />
@ -110,7 +123,7 @@
</celestialObject>
<!-- Earth is the overworld (dimension.id is 0) -->
<celestialObject group="solarSystem" name="earth">
<celestialObject id="earth">
<parent>
<!-- coordinates in the solar system, measured in blocks -->
<center x="-40000" z="20000" />
@ -128,7 +141,7 @@
<render red="0.50" green="0.50" blue="1.00" alpha="0.08" />
<!-- Hell is the nether. It's located below earth. In other words, falling below bedrock will drop you to the nether... -->
<celestialObject group="solarSystem" name="hell">
<celestialObject id="hell">
<parent>
<center x="0" z="0" />
</parent>
@ -140,7 +153,7 @@
</celestialObject>
<!-- Pluto is The End. It's a far planet. -->
<celestialObject group="solarSystem" name="pluto">
<celestialObject id="pluto">
<parent>
<center x="90000" z="70000" />
</parent>