10 Commits

Author SHA1 Message Date
eb5aa59941 Removed plain sand block and tile; incremented version
To be honest, I kinda forgot to increment version in last commit, so I
decided to make a pointless change to justify an entire commit =\
2021-09-11 21:12:42 +03:00
409bbdb680 Merge branch 'save-world' 2021-09-11 19:42:36 +03:00
a85fc27f8b Added _UNFINISHED_ water, beaches and mantle
- Refactored terrain generation
- Added PiecewiseLinearFunction
- Added some placeholder content
  - Added Test:Water, the solid, opaque water
  - Added beaches
  - Added Test:Mantle
- Tweaked rock distribution parameters
2021-08-31 17:27:08 +03:00
711e4a2bb4 Added formatting templates guide for Intellij IDEA 2021-08-30 19:51:28 +03:00
f74c731a3d Fixed GUI buttons and a rare crash on startup 2021-08-27 12:20:58 +03:00
98c383bf7d Fixed a stupid typo in previous commit 2021-08-26 12:11:21 +03:00
dd80df2cf2 Fixed a GUI reassembly issue and added cursor disabling suppression
- Buttons no longer reassemble every frame
- Label.setFont() no longer requests reassembly
- Component.reassembleAt now actually works
- Using a very long flag, cursor capturing can be disabled to facilitate
GUI debugging
2021-08-26 12:09:22 +03:00
1727a2a4a1 Added Object fields to StatefulObjects and added some utility methods
- Added ObjectStateField
- Added WorldGenericContextRO.findClosestEntity, .forEachEntity
- Added VectorUtil.lookAt, .distance{,Sq}
2021-08-25 16:47:56 +03:00
20fb8f0597 Fixed missing popTrasnform in Statie render 2021-08-24 15:12:35 +03:00
1d28f32865 Implemented entity spawning and despawning and changed some stuff
- Non-player entities can now be added and removed properly
  - WorldLogic.spawnEntity can be used to add entity and create an
entity ID
- Statie is back, more beautiful than ever!
  - Place Test:StatieSpawner block and wait to make her spawn
- TPS display now features a visual tick indicator
- Updated Fern texture
2021-08-24 13:59:28 +03:00
75 changed files with 2009 additions and 130 deletions

View File

@ -41,4 +41,17 @@ Run configurations are used by Intellij IDEA to specify how a project must be ru
8. Append `\run` to the 'Working directory' field. Alternatively, specify another location outside of the project's root directory.
9. Click 'Apply' to save changes.
Step 8 is required to specify that the game must run in some directory other than the project root, which is the default in Intellij IDEA.
Step 8 is required to specify that the game must run in some directory other than the project root, which is the default in Intellij IDEA.
### Applying formatting templates
Windcorp's Progressia repository is formatted with a style defined for Eclipse IDE (sic) in
`templates_and_presets/eclipse_ide`.
Please apply these templates to the project to automatically format the source in a similar fashion.
1. In project context menu, click 'File->Properties'. (`Ctrl+Alt+S`)
2. In 'Editor' > 'Code Style' > 'Java', press gear icon, then click 'Import Scheme' > 'Eclipse code style'
3. In Scheme select 'Project'
4. Open the file `templates_and_presets/eclipse_ide/FormatterProfile.xml` in 'Select Path'.
5. Inside 'Import Scheme' widow click 'Current Scheme' check box after press OK

View File

@ -19,6 +19,7 @@
package ru.windcorp.progressia.client.graphics.backend;
import glm.vec._2.i.Vec2i;
import org.lwjgl.glfw.GLFWVidMode;
import static org.lwjgl.glfw.GLFW.*;
@ -42,6 +43,13 @@ public class GraphicsBackend {
private static boolean vSyncEnabled = false;
private static boolean isGLFWInitialized = false;
private static boolean isOpenGLInitialized = false;
private static boolean allowDisablingCursor;
static {
String key = GraphicsBackend.class.getName() + ".allowDisablingCursor";
allowDisablingCursor = Boolean.parseBoolean(System.getProperty(key, "true"));
}
private static boolean forceCursorToCenter = false;
private GraphicsBackend() {
}
@ -114,6 +122,10 @@ public class GraphicsBackend {
frameLength = now - frameStart;
frameStart = now;
}
if (forceCursorToCenter) {
glfwSetCursorPos(windowHandle, FRAME_SIZE.x / 2.0, FRAME_SIZE.y / 2.0);
}
}
static void endFrame() {
@ -194,10 +206,18 @@ public class GraphicsBackend {
}
public static boolean isMouseCaptured() {
if (!allowDisablingCursor) {
return forceCursorToCenter;
}
return glfwGetInputMode(windowHandle, GLFW_CURSOR) == GLFW_CURSOR_DISABLED;
}
public static void setMouseCaptured(boolean capture) {
if (!allowDisablingCursor) {
forceCursorToCenter = capture;
return;
}
int mode = capture ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL;
glfwSetInputMode(windowHandle, GLFW_CURSOR, mode);

View File

@ -124,6 +124,7 @@ public abstract class BasicButton extends Component {
public void setPressed(boolean isPressed) {
if (this.isPressed != isPressed) {
this.isPressed = isPressed;
requestReassembly();
if (isPressed) {
takeFocus();

View File

@ -807,7 +807,7 @@ public class Component extends Named {
for (ARTrigger trigger : triggers) {
if (!autoReassemblyTriggerObjects.containsKey(trigger)) {
Object triggerObject = createTriggerObject(trigger);
addListener(trigger);
addListener(triggerObject);
autoReassemblyTriggerObjects.put(trigger, triggerObject);
}
}

View File

@ -85,7 +85,6 @@ public class Label extends Component {
public void setFont(Font font) {
this.font = font;
requestReassembly();
}
public String getCurrentText() {

View File

@ -20,10 +20,12 @@ package ru.windcorp.progressia.client.graphics.model;
import java.util.Map;
import glm.mat._4.Mat4;
import glm.vec._3.Vec3;
import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.backend.Usage;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.rels.AbsFace;
public class Shapes {
@ -259,6 +261,34 @@ public class Shapes {
public PppBuilder setSize(float size) {
return this.setSize(size, size, size);
}
public PppBuilder centerAt(float x, float y, float z) {
origin.set(x, y, z);
origin.mul(2);
origin.sub(width);
origin.sub(height);
origin.sub(depth);
origin.div(2);
return this;
}
public PppBuilder apply(Mat4 transform) {
VectorUtil.applyMat4(origin, transform);
VectorUtil.rotateOnly(width, transform);
VectorUtil.rotateOnly(height, transform);
VectorUtil.rotateOnly(depth, transform);
return this;
}
public PppBuilder scale(float factor) {
origin.mul(factor);
width.mul(factor);
height.mul(factor);
depth.mul(factor);
return this;
}
public PppBuilder flip() {
this.flip = true;

View File

@ -28,6 +28,20 @@ public abstract class AbstractStatefulObjectLayout
public AbstractStatefulObjectLayout(String objectId) {
super(objectId);
}
@Override
public StateStorage createStorage() {
StateStorage storage = instantiateStorage();
int fieldCount = getFieldCount();
for (int i = 0; i < fieldCount; ++i) {
getField(i).setDefault(storage);
}
return storage;
}
protected abstract StateStorage instantiateStorage();
protected abstract int getFieldCount();

View File

@ -0,0 +1,64 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.state;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public interface Encodable {
/**
* Sets the state of this object according to the binary representation read
* from {@code input}. If {@code context == COMMS}, the state of local
* fields is unspecified after this operation.
*
* @param input a {@link DataInput} that a state can be read from
* @param context the context
* @throws IOException if the state is encoded poorly or an error occurs
* in {@code input}
*/
void read(DataInput input, IOContext context) throws IOException;
/**
* Writes the binary representation of the state of this object to the
* {@code output}.
*
* @param output a {@link DataOutput} that a state can be written to
* @param context the context
* @throws IOException if an error occurs in {@code output}
*/
void write(DataOutput output, IOContext context) throws IOException;
/**
* Turns {@code destination} into a deep copy of this object.
* <p>
* Changes the provided object so that:
* <ul>
* <li>the provided object equals this object; and</li>
* <li>the provided object is independent of this object, meaning no change
* to {@code destination} can affect this object.</li>
* </ul>
*
* @param destination the object to copy this object into. Runtime class
* must match this class
* @return {@code destination}
*/
void copy(Encodable destination);
}

View File

@ -19,11 +19,14 @@
package ru.windcorp.progressia.common.state;
import gnu.trove.map.TIntIntMap;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntIntHashMap;
import gnu.trove.map.hash.TIntObjectHashMap;
public class HashMapStateStorage extends StateStorage {
private final TIntIntMap ints = new TIntIntHashMap();
private final TIntObjectMap<Object> objects = new TIntObjectHashMap<>();
@Override
public int getInt(int index) {
@ -34,5 +37,15 @@ public class HashMapStateStorage extends StateStorage {
public void setInt(int index, int value) {
ints.put(index, value);
}
@Override
public Object getObject(int index) {
return objects.get(index);
}
@Override
public void setObject(int index, Object object) {
objects.put(index, object);
}
}

View File

@ -20,6 +20,9 @@ package ru.windcorp.progressia.common.state;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import ru.windcorp.progressia.common.state.codec.ObjectCodec;
public class InspectingStatefulObjectLayout
extends AbstractStatefulObjectLayout {
@ -33,7 +36,7 @@ public class InspectingStatefulObjectLayout
}
@Override
public StateStorage createStorage() {
public StateStorage instantiateStorage() {
return new HashMapStateStorage();
}
@ -81,6 +84,31 @@ public class InspectingStatefulObjectLayout
}
}
private class Obj<T> implements StateFieldBuilder.Obj<T> {
private final ObjectCodec<T> codec;
private final Supplier<T> defaultValue;
public Obj(ObjectCodec<T> codec, Supplier<T> defaultValue) {
this.codec = codec;
this.defaultValue = defaultValue;
}
@Override
public ObjectStateField<T> build() {
return registerField(
new ObjectStateField<T>(
id,
isLocal,
fieldIndexCounters.getObjectsThenIncrement(),
codec,
defaultValue
)
);
}
}
private final String id;
@ -94,6 +122,11 @@ public class InspectingStatefulObjectLayout
public Int ofInt() {
return new Int();
}
@Override
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
return new Obj<T>(codec, defaultValue);
}
@Override
public StateFieldBuilder setLocal(boolean isLocal) {

View File

@ -78,5 +78,10 @@ public class IntStateField extends StateField {
public boolean areEqual(StatefulObject a, StatefulObject b) {
return get(a) == get(b);
}
@Override
public void setDefault(StateStorage storage) {
storage.setInt(getIndex(), 0);
}
}

View File

@ -0,0 +1,107 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.state;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.function.Supplier;
import ru.windcorp.progressia.common.state.codec.ObjectCodec;
public class ObjectStateField<T> extends StateField {
private final ObjectCodec<T> codec;
private final Supplier<T> defaultValue;
public ObjectStateField(
String id,
boolean isLocal,
int index,
ObjectCodec<T> codec,
Supplier<T> defaultValue
) {
super(id, isLocal, index);
this.codec = codec;
this.defaultValue = defaultValue;
}
public ObjectCodec<T> getCodec() {
return codec;
}
@SuppressWarnings("unchecked")
public T get(StatefulObject object) {
return (T) object.getStorage().getObject(getIndex());
}
public void setNow(StatefulObject object, T value) {
object.getStorage().setObject(getIndex(), value);
}
public void set(StateChanger changer, T value) {
changer.setObject(this, value);
}
@Override
public void read(
StatefulObject object,
DataInput input,
IOContext context
)
throws IOException {
T previous = get(object);
T result = codec.read(previous, input, context);
object.getStorage().setObject(getIndex(), result);
}
@Override
public void write(
StatefulObject object,
DataOutput output,
IOContext context
)
throws IOException {
codec.write(object.getStorage().getObject(getIndex()), output, context);
}
@Override
public void copy(StatefulObject from, StatefulObject to) {
setNow(to, get(from));
}
@Override
public int computeHashCode(StatefulObject object) {
return codec.computeHashCode(get(object));
}
@Override
public boolean areEqual(StatefulObject a, StatefulObject b) {
return codec.areEqual(get(a), get(b));
}
@Override
public void setDefault(StateStorage storage) {
storage.setObject(getIndex(), defaultValue.get());
}
}

View File

@ -21,9 +21,11 @@ package ru.windcorp.progressia.common.state;
public class OptimizedStateStorage extends StateStorage {
private final int[] ints;
private final Object[] objects;
public OptimizedStateStorage(PrimitiveCounters sizes) {
this.ints = new int[sizes.getInts()];
this.objects = new Object[sizes.getObjects()];
}
@Override
@ -35,5 +37,15 @@ public class OptimizedStateStorage extends StateStorage {
public void setInt(int index, int value) {
ints[index] = value;
}
@Override
public Object getObject(int index) {
return objects[index];
}
@Override
public void setObject(int index, Object object) {
objects[index] = object;
}
}

View File

@ -19,9 +19,12 @@
package ru.windcorp.progressia.common.state;
import java.util.List;
import java.util.function.Supplier;
import com.google.common.collect.ImmutableList;
import ru.windcorp.progressia.common.state.codec.ObjectCodec;
public class OptimizedStatefulObjectLayout
extends AbstractStatefulObjectLayout {
@ -49,7 +52,7 @@ public class OptimizedStatefulObjectLayout
}
@Override
public StateStorage createStorage() {
public StateStorage instantiateStorage() {
return new OptimizedStateStorage(sizes);
}
@ -71,6 +74,17 @@ public class OptimizedStatefulObjectLayout
}
};
}
@Override
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
return new Obj<T>() {
@SuppressWarnings("unchecked")
@Override
public ObjectStateField<T> build() {
return (ObjectStateField<T>) result;
}
};
}
@Override
public StateFieldBuilder setLocal(boolean isLocal) {

View File

@ -21,12 +21,14 @@ package ru.windcorp.progressia.common.state;
class PrimitiveCounters {
private int ints = 0;
private int objects = 0;
public PrimitiveCounters() {
}
public PrimitiveCounters(PrimitiveCounters copyFrom) {
this.ints = copyFrom.ints;
this.objects = copyFrom.objects;
}
public int getInts() {
@ -36,5 +38,13 @@ class PrimitiveCounters {
public int getIntsThenIncrement() {
return this.ints++;
}
public int getObjects() {
return objects;
}
public int getObjectsThenIncrement() {
return this.objects++;
}
}

View File

@ -21,5 +21,6 @@ package ru.windcorp.progressia.common.state;
public interface StateChanger {
void setInt(IntStateField field, int value);
<T> void setObject(ObjectStateField<T> field, T value);
}

View File

@ -66,5 +66,7 @@ public abstract class StateField extends Namespaced {
public abstract int computeHashCode(StatefulObject object);
public abstract boolean areEqual(StatefulObject a, StatefulObject b);
public abstract void setDefault(StateStorage storage);
}

View File

@ -18,13 +18,58 @@
package ru.windcorp.progressia.common.state;
import java.util.function.Supplier;
import ru.windcorp.progressia.common.state.codec.ObjectCodec;
import ru.windcorp.progressia.common.state.codec.ObjectCodecRegistry;
public interface StateFieldBuilder {
public static interface Int {
IntStateField build();
}
public static interface Obj<T> {
ObjectStateField<T> build();
}
Int ofInt();
<T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue);
default <T> Obj<T> of(Class<T> clazz, Supplier<T> defaultValue) {
ObjectCodec<T> codec = ObjectCodecRegistry.get(clazz);
return of(codec, defaultValue);
}
default <T> Obj<T> of(ObjectCodec<T> codec, T defaultValue) {
return of(codec, (Supplier<T>) () -> codec.copy(defaultValue, null));
}
default <T> Obj<T> of(Class<T> clazz, T defaultValue) {
ObjectCodec<T> codec = ObjectCodecRegistry.get(clazz);
return of(codec, (Supplier<T>) () -> codec.copy(defaultValue, null));
}
default <T> Obj<T> of(ObjectCodec<T> codec) {
return of(codec, (Supplier<T>) () -> null);
}
default <T> Obj<T> of(Class<T> clazz) {
ObjectCodec<T> codec = ObjectCodecRegistry.get(clazz);
return of(codec, (Supplier<T>) () -> null);
}
@SuppressWarnings("unchecked")
default <T> Obj<T> def(Supplier<T> defaultValue) {
Class<T> clazz = (Class<T>) defaultValue.get().getClass();
return of(clazz, defaultValue);
}
@SuppressWarnings("unchecked")
default <T> Obj<T> def(T defaultValue) {
return of((Class<T>) defaultValue.getClass(), defaultValue);
}
StateFieldBuilder setLocal(boolean isLocal);

View File

@ -23,5 +23,9 @@ public abstract class StateStorage {
public abstract int getInt(int index);
public abstract void setInt(int index, int value);
public abstract Object getObject(int index);
public abstract void setObject(int index, Object object);
}

View File

@ -52,7 +52,7 @@ import ru.windcorp.progressia.common.util.namespaces.Namespaced;
* type.</li>
* </ul>
*/
public abstract class StatefulObject extends Namespaced {
public abstract class StatefulObject extends Namespaced implements Encodable {
private final StatefulObjectLayout layout;
@ -133,6 +133,7 @@ public abstract class StatefulObject extends Namespaced {
* @throws IOException if the state is encoded poorly or an error occurs
* in {@code input}
*/
@Override
public void read(DataInput input, IOContext context) throws IOException {
getLayout().read(this, input, context);
}
@ -145,6 +146,7 @@ public abstract class StatefulObject extends Namespaced {
* @param context the context
* @throws IOException if an error occurs in {@code output}
*/
@Override
public void write(DataOutput output, IOContext context) throws IOException {
getLayout().write(this, output, context);
}
@ -166,7 +168,8 @@ public abstract class StatefulObject extends Namespaced {
*
* @param destination the object to copy this object into.
*/
public StatefulObject copy(StatefulObject destination) {
@Override
public void copy(Encodable destination) {
Objects.requireNonNull(destination, "destination");
if (destination == this) {
@ -182,8 +185,7 @@ public abstract class StatefulObject extends Namespaced {
);
}
getLayout().copy(this, destination);
return destination;
getLayout().copy(this, (StatefulObject) destination);
}
/**

View File

@ -0,0 +1,52 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.state.codec;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Objects;
import ru.windcorp.progressia.common.state.Encodable;
import ru.windcorp.progressia.common.state.IOContext;
public class EncodableCodec extends ReusableObjectCodec<Encodable> {
public EncodableCodec() {
super(Encodable.class);
}
@Override
protected Encodable doRead(Encodable previous, DataInput input, IOContext context) throws IOException {
previous.read(input, context);
return previous;
}
@Override
protected void doWrite(Encodable obj, DataOutput output, IOContext context) throws IOException {
obj.write(output, context);
}
@Override
protected Encodable doCopy(Encodable object, Encodable previous) {
Objects.requireNonNull(previous, "previous");
object.copy(previous);
return previous;
}
}

View File

@ -0,0 +1,43 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.state.codec;
import java.io.DataInput;
import java.io.IOException;
import ru.windcorp.progressia.common.state.IOContext;
public abstract class ImmutableObjectCodec<T> extends ObjectCodec<T> {
public ImmutableObjectCodec(Class<T> clazz) {
super(clazz);
}
@Override
public final T copy(T object, T previous) {
return object;
}
@Override
protected final T doRead(T previous, DataInput input, IOContext context) throws IOException {
return doRead(input, context);
}
protected abstract T doRead(DataInput input, IOContext context) throws IOException;
}

View File

@ -0,0 +1,73 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.state.codec;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Objects;
import ru.windcorp.progressia.common.state.IOContext;
public abstract class ObjectCodec<T> {
private final Class<T> clazz;
public ObjectCodec(Class<T> clazz) {
this.clazz = clazz;
}
public Class<T> getDataType() {
return clazz;
}
@SuppressWarnings("unchecked")
public final T read(Object previous, DataInput input, IOContext context) throws IOException {
assert previous == null || clazz.isInstance(previous)
: "Cannot use codec " + this + " on object of type " + previous.getClass();
T result = doRead((T) previous, input, context);
assert result == null || clazz.isInstance(previous)
: "Codec " + this + " read object of type " + previous.getClass();
return result;
}
protected abstract T doRead(T previous, DataInput input, IOContext context) throws IOException;
@SuppressWarnings("unchecked")
public final void write(Object value, DataOutput output, IOContext context) throws IOException {
assert value == null || clazz.isInstance(value)
: "Cannot use codec " + this + " on object of type " + value.getClass();
doWrite((T) value, output, context);
}
protected abstract void doWrite(T obj, DataOutput output, IOContext context) throws IOException;
public abstract T copy(T object, T previous);
public int computeHashCode(T object) {
return Objects.hashCode(object);
}
public boolean areEqual(T a, T b) {
return Objects.equals(a, b);
}
}

View File

@ -0,0 +1,49 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.state.codec;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import ru.windcorp.progressia.common.state.Encodable;
public class ObjectCodecRegistry {
private static final Map<Class<?>, ObjectCodec<?>> CODECS = Collections.synchronizedMap(new HashMap<>());
private static final EncodableCodec ENCODABLE_FALLBACK = new EncodableCodec();
public static void register(ObjectCodec<?> codec) {
CODECS.put(codec.getDataType(), codec);
}
@SuppressWarnings("unchecked")
public static <T> ObjectCodec<T> get(Class<T> clazz) {
ObjectCodec<?> codec = CODECS.get(clazz);
if (codec != null) {
return (ObjectCodec<T>) codec;
}
if (Encodable.class.isAssignableFrom(clazz)) {
return (ObjectCodec<T>) ENCODABLE_FALLBACK;
}
throw new IllegalArgumentException("No codec registered for class " + clazz);
}
}

View File

@ -0,0 +1,42 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.state.codec;
public abstract class ReusableObjectCodec<T> extends ObjectCodec<T> {
public ReusableObjectCodec(Class<T> clazz) {
super(clazz);
}
@Override
public final T copy(T object, T previous) {
if (object == null) {
return null;
}
T result = doCopy(object, previous);
assert result != null : "copy() returned null";
assert areEqual(object, result) : "copy() does not equal original: " + result + " != " + object;
return result;
}
protected abstract T doCopy(T object, T previous);
}

View File

@ -199,6 +199,63 @@ public class VectorUtil {
return rotateOnly(inOut, mat, inOut);
}
public static Mat4 lookAt(Mat4 applyTo, Vec3 target, Vec3 up, Mat4 output) {
if (output == null) {
output = new Mat4();
}
Mat4 lookAtTransform = Matrices.grab4();
// Adapted from Glm.lookAt - we use Z as up
// f(normalize(target))
float fX = target.x;
float fY = target.y;
float fZ = target.z;
float inverseSqrt = 1f / (float) Math.sqrt(fX * fX + fY * fY + fZ * fZ);
fX *= inverseSqrt;
fY *= inverseSqrt;
fZ *= inverseSqrt;
// s(normalize(cross(up, f)))
float sX = up.y * fZ - up.z * fY;
float sY = up.z * fX - up.x * fZ;
float sZ = up.x * fY - up.y * fX;
inverseSqrt = 1.0f / (float) Math.sqrt(sX * sX + sY * sY + sZ * sZ);
sX *= inverseSqrt;
sY *= inverseSqrt;
sZ *= inverseSqrt;
// u(cross(f, s))
float uX = fY * sZ - fZ * sY;
float uY = fZ * sX - fX * sZ;
float uZ = fX * sY - fY * sX;
lookAtTransform.m00 = fX;
lookAtTransform.m01 = fY;
lookAtTransform.m02 = fZ;
lookAtTransform.m03 = 0f;
lookAtTransform.m10 = sX;
lookAtTransform.m11 = sY;
lookAtTransform.m12 = sZ;
lookAtTransform.m13 = 0f;
lookAtTransform.m20 = uX;
lookAtTransform.m21 = uY;
lookAtTransform.m22 = uZ;
lookAtTransform.m23 = 0f;
lookAtTransform.m30 = 0;
lookAtTransform.m31 = 0;
lookAtTransform.m32 = 0;
lookAtTransform.m33 = 1f;
applyTo.mul(lookAtTransform, output);
Matrices.release(lookAtTransform);
return output;
}
public static Mat4 lookAt(Vec3 center, Vec3 up, Mat4 inOut) {
return lookAt(inOut, center, up, inOut);
}
public static Vec3 rotate(Vec3 in, Vec3 axis, float angle, Vec3 out) {
if (out == null) {
out = new Vec3();
@ -269,6 +326,20 @@ public class VectorUtil {
public static Vec3 projectOnVector(Vec3 inOut, Vec3 vector) {
return projectOnVector(inOut, vector);
}
public static float distanceSq(Vec3 a, Vec3 b) {
float x = a.x - b.x;
float y = a.y - b.y;
float z = a.z - b.z;
return x * x + y * y + z * z;
}
public static float distance(Vec3 a, Vec3 b) {
float x = a.x - b.x;
float y = a.y - b.y;
float z = a.z - b.z;
return (float) Math.sqrt(x * x + y * y + z * z);
}
public static Vec3 linearCombination(
Vec3 va,

View File

@ -0,0 +1,25 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.util.math;
@FunctionalInterface
public interface FloatFunction {
float apply(float x);
}

View File

@ -0,0 +1,24 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.util.math;
public interface FloatFunction2D {
float apply(float x, float y);
}

View File

@ -0,0 +1,24 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.util.math;
public interface FloatFunction3D {
float apply(float x, float y, float z);
}

View File

@ -0,0 +1,124 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.util.math;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import glm.vec._2.Vec2;
public class PiecewiseLinearFunction implements FloatFunction {
public static class Builder {
private final List<Vec2> points = new ArrayList<>();
private float slopeAtNegInf = 0;
private float slopeAtPosInf = 0;
public Builder add(float x, float y) {
points.add(new Vec2(x, y));
return this;
}
public Builder setNegativeSlope(float slope) {
slopeAtNegInf = slope;
return this;
}
public Builder setPositiveSlope(float slope) {
slopeAtPosInf = slope;
return this;
}
public Builder setDefaultUndefined() {
slopeAtPosInf = Float.NaN;
slopeAtNegInf = Float.NaN;
return this;
}
public PiecewiseLinearFunction build() {
float[] pointXs = new float[points.size()];
float[] pointYs = new float[points.size()];
points.sort(Comparator.comparingDouble(v -> v.x));
for (int i = 0; i < points.size(); ++i) {
pointXs[i] = points.get(i).x;
pointYs[i] = points.get(i).y;
}
return new PiecewiseLinearFunction(pointXs, pointYs, slopeAtNegInf, slopeAtPosInf);
}
}
public static Builder builder() {
return new Builder();
}
/**
* The set of the X coordinates of all defining points, sorted in increasing order
*/
private final float[] pointXs;
/**
* The set of the Y coordinates of all defining points, sorted to match the order of {@link #pointXs}
*/
private final float[] pointYs;
/**
* Slope of the segment (-inf; x[0]), or NaN to exclude the segment from the function
*/
private final float slopeAtNegInf;
/**
* Slope of the segment (x[x.length - 1]; +inf), or NaN to exclude the segment from the function
*/
private final float slopeAtPosInf;
protected PiecewiseLinearFunction(float[] pointXs, float[] pointYs, float slopeAtNegInf, float slopeAtPosInf) {
this.pointXs = pointXs;
this.pointYs = pointYs;
this.slopeAtNegInf = slopeAtNegInf;
this.slopeAtPosInf = slopeAtPosInf;
}
@Override
public float apply(float x) {
int index = Arrays.binarySearch(pointXs, x);
if (index >= 0) {
// Wow, exact match, me surprised
return pointYs[index];
}
int bigger = -index - 1;
int smaller = bigger - 1;
if (smaller == -1) {
return pointYs[bigger] + (x - pointXs[bigger]) * slopeAtNegInf;
} else if (bigger == pointXs.length) {
return pointYs[smaller] + (x - pointXs[smaller]) * slopeAtPosInf;
} else {
float t = (x - pointXs[smaller]) / (pointXs[bigger] - pointXs[smaller]);
return pointYs[smaller] * (1 - t) + pointYs[bigger] * t;
}
}
}

View File

@ -19,8 +19,11 @@ package ru.windcorp.progressia.common.world.generic.context;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Predicate;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.context.Context;
import ru.windcorp.progressia.common.world.generic.*;
import ru.windcorp.progressia.common.world.rels.RelFace;
@ -141,16 +144,52 @@ public interface WorldGenericContextRO<
*/
E getEntity(long entityId);
/*
* Convenience methods
*/
default void forEachEntity(Consumer<E> action) {
getEntities().forEach(action);
}
default E findClosestEntity(Vec3 location, Predicate<E> filter, float maxDistance) {
if (maxDistance <= 0) {
return null;
}
E result = getEntities().stream().filter(filter).min((a, b) -> {
float aDistance = VectorUtil.distanceSq(location, a.getPosition());
float bDistance = VectorUtil.distanceSq(location, b.getPosition());
return Float.compare(aDistance, bDistance);
}).orElse(null);
if (result == null) {
return null;
}
if (Float.isInfinite(maxDistance)) {
return result;
}
if (VectorUtil.distanceSq(location, result.getPosition()) > maxDistance * maxDistance) {
return null;
}
return result;
}
default E findClosestEntity(Vec3 location, float maxDistance) {
return findClosestEntity(location, e -> true, maxDistance);
}
/*
* Subcontexting
*/
@Override
BlockGenericContextRO<B, T, E> push(Vec3i location);
@Override
TileStackGenericContextRO<B, T, E> push(Vec3i location, RelFace face);
@Override
TileGenericContextRO<B, T, E> push(Vec3i location, RelFace face, int layer);

View File

@ -21,8 +21,6 @@ package ru.windcorp.progressia.server;
import java.util.function.Consumer;
import java.util.function.Function;
import org.apache.logging.log4j.LogManager;
import com.google.common.eventbus.EventBus;
import glm.vec._3.i.Vec3i;
@ -353,7 +351,6 @@ public class Server {
* reason
*/
public void shutdown(String message) {
LogManager.getLogger().warn("Server.shutdown() is not yet implemented");
serverThread.stop();
getWorld().getContainer().close();
}

View File

@ -96,7 +96,7 @@ public class ClientManager {
}
public void processPackets() {
getClients().forEach(CommsChannel::processPackets);
clients.forEach(CommsChannel::processPackets);
}
/**
@ -146,7 +146,7 @@ public class ClientManager {
return;
if (!(c instanceof ClientPlayer))
return;
if (!((ClientPlayer) c).isChunkVisible(entityId))
if (!((ClientPlayer) c).isEntityVisible(entityId))
return;
c.sendPacket(packet);
});

View File

@ -19,6 +19,9 @@
package ru.windcorp.progressia.server.comms;
import glm.vec._3.i.Vec3i;
import gnu.trove.TCollections;
import gnu.trove.set.TLongSet;
import gnu.trove.set.hash.TLongHashSet;
import ru.windcorp.progressia.common.world.generic.ChunkSet;
import ru.windcorp.progressia.common.world.generic.ChunkSets;
import ru.windcorp.progressia.server.Player;
@ -53,8 +56,19 @@ public abstract class ClientPlayer extends ClientChat {
return player.getServer().getLoadManager().getVisionManager().getVisibleChunks(player);
}
public boolean isChunkVisible(long entityId) {
return true;
public boolean isEntityVisible(long entityId) {
if (player == null)
return false;
return player.getServer().getLoadManager().getVisionManager().isEntityVisible(entityId, player);
}
private static final TLongSet EMPTY_TLONGSET = TCollections.unmodifiableSet(new TLongHashSet(0));
public TLongSet getVisibleEntities(Player player) {
if (player == null) {
return EMPTY_TLONGSET;
}
return player.getServer().getLoadManager().getVisionManager().getVisibleEntities(player);
}
}

View File

@ -17,10 +17,14 @@
*/
package ru.windcorp.progressia.server.management.load;
import java.util.HashSet;
import java.util.Set;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.PacketRevokeChunk;
import ru.windcorp.progressia.common.world.PacketSendChunk;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.server.Player;
import ru.windcorp.progressia.server.Server;
@ -144,6 +148,11 @@ public class ChunkManager {
return false;
}
// TODO allow entities to be saved first
Set<EntityData> entitiesToRemove = new HashSet<>();
world.forEachEntityInChunk(chunkPos, entitiesToRemove::add);
entitiesToRemove.forEach(world::removeEntity);
world.removeChunk(chunk);
getContainer().save(chunk, getServer().getWorld().getData(), getServer());

View File

@ -25,6 +25,9 @@ import java.util.function.Consumer;
import com.google.common.eventbus.Subscribe;
import glm.vec._3.i.Vec3i;
import gnu.trove.TCollections;
import gnu.trove.set.TLongSet;
import gnu.trove.set.hash.TLongHashSet;
import ru.windcorp.progressia.common.world.generic.ChunkSet;
import ru.windcorp.progressia.common.world.generic.ChunkSets;
import ru.windcorp.progressia.server.Player;
@ -85,6 +88,28 @@ public class VisionManager {
return vision.getVisibleChunks();
}
public boolean isEntityVisible(long entityId, Player player) {
PlayerVision vision = getVision(player, false);
if (vision == null) {
return false;
}
return vision.isEntityVisible(entityId);
}
private static final TLongSet EMPTY_TLONGSET = TCollections.unmodifiableSet(new TLongHashSet(0));
public TLongSet getVisibleEntities(Player player) {
PlayerVision vision = getVision(player, false);
if (vision == null) {
return EMPTY_TLONGSET;
}
return vision.getVisibleEntities();
}
/**
* @return the loadManager
*/

View File

@ -15,12 +15,13 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.server.world;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import glm.Glm;
import glm.vec._3.i.Vec3i;
@ -52,7 +53,7 @@ public class DefaultWorldLogic implements WorldLogic {
public DefaultWorldLogic(DefaultWorldData data, Server server, WorldGenerator generator, WorldContainer container, WorldAccessor accessor) {
this.data = data;
this.server = server;
this.generator = generator;
data.setGravityModel(getGenerator().getGravityModel());
@ -87,12 +88,33 @@ public class DefaultWorldLogic implements WorldLogic {
public Collection<EntityData> getEntities() {
return getData().getEntities();
}
@Override
public EntityData getEntity(long entityId) {
return getData().getEntity(entityId);
}
@Override
public void spawnEntity(EntityData entity) {
Objects.requireNonNull(entity, "entity");
if (entity.getEntityId() != EntityData.NULL_ENTITY_ID) {
throw new IllegalArgumentException(
"Entity ID of entity " + entity
+ " is not unassigned; use WorldData.addEntity to add entity with assigned entity ID"
);
}
long entityId;
// TODO this should be synchronized on the entity set
do {
entityId = server.getAdHocRandom().nextLong();
} while (entityId == EntityData.NULL_ENTITY_ID || getEntity(entityId) != null);
entity.setEntityId(entityId);
getData().addEntity(entity);
}
public Evaluation getTickEntitiesTask() {
return tickEntitiesTask;
}
@ -116,36 +138,54 @@ public class DefaultWorldLogic implements WorldLogic {
public DefaultChunkData generate(Vec3i chunkPos) {
DefaultChunkData chunk = getGenerator().generate(chunkPos);
if (!Glm.equals(chunkPos, chunk.getPosition())) {
throw CrashReports.report(null, "Generator %s has generated a chunk at (%d; %d; %d) when requested to generate a chunk at (%d; %d; %d)",
throw CrashReports.report(
null,
"Generator %s has generated a chunk at (%d; %d; %d) when requested to generate a chunk at (%d; %d; %d)",
getGenerator(),
chunk.getX(), chunk.getY(), chunk.getZ(),
chunkPos.x, chunkPos.y, chunkPos.z
chunk.getX(),
chunk.getY(),
chunk.getZ(),
chunkPos.x,
chunkPos.y,
chunkPos.z
);
}
if (getData().getChunk(chunk.getPosition()) != chunk) {
if (isChunkLoaded(chunkPos)) {
throw CrashReports.report(null, "Generator %s has returned a chunk different to the chunk that is located at (%d; %d; %d)",
throw CrashReports.report(
null,
"Generator %s has returned a chunk different to the chunk that is located at (%d; %d; %d)",
getGenerator(),
chunkPos.x, chunkPos.y, chunkPos.z
chunkPos.x,
chunkPos.y,
chunkPos.z
);
} else {
throw CrashReports.report(null, "Generator %s has returned a chunk that is not loaded when requested to generate a chunk at (%d; %d; %d)",
throw CrashReports.report(
null,
"Generator %s has returned a chunk that is not loaded when requested to generate a chunk at (%d; %d; %d)",
getGenerator(),
chunkPos.x, chunkPos.y, chunkPos.z
chunkPos.x,
chunkPos.y,
chunkPos.z
);
}
}
if (!getChunk(chunk).isReady()) {
throw CrashReports.report(null, "Generator %s has returned a chunk that is not ready when requested to generate a chunk at (%d; %d; %d)",
throw CrashReports.report(
null,
"Generator %s has returned a chunk that is not ready when requested to generate a chunk at (%d; %d; %d)",
getGenerator(),
chunkPos.x, chunkPos.y, chunkPos.z
chunkPos.x,
chunkPos.y,
chunkPos.z
);
}
return chunk;
}

View File

@ -21,9 +21,12 @@ import java.util.Collection;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.rels.BlockFace;
public interface WorldLogic extends WorldLogicRO {
void spawnEntity(EntityData entity);
/*
* Override return types

View File

@ -24,7 +24,6 @@ import java.util.List;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.DecodingException;
@ -32,7 +31,7 @@ import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer;
import ru.windcorp.progressia.server.world.generation.surface.TerrainSupplier;
public class PlanetGenerator extends AbstractWorldGenerator<Boolean> {
@ -46,7 +45,7 @@ public class PlanetGenerator extends AbstractWorldGenerator<Boolean> {
Server server,
Planet planet,
SurfaceFloatField heightMap,
FloatRangeMap<TerrainLayer> layers,
TerrainSupplier terrain,
List<SurfaceFeature> features
) {
super(id, server, Boolean.class, "Test:PlanetGravityModel");
@ -56,7 +55,7 @@ public class PlanetGenerator extends AbstractWorldGenerator<Boolean> {
PlanetGravityModel model = (PlanetGravityModel) this.getGravityModel();
model.configure(planet.getGravityModelSettings());
this.terrainGenerator = new PlanetTerrainGenerator(this, heightMap, layers);
this.terrainGenerator = new PlanetTerrainGenerator(this, heightMap, terrain);
this.featureGenerator = new PlanetFeatureGenerator(this, features);
}

View File

@ -21,7 +21,6 @@ import java.util.Map;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.Coordinates;
@ -33,7 +32,7 @@ import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.generation.surface.Surface;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceTerrainGenerator;
import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer;
import ru.windcorp.progressia.server.world.generation.surface.TerrainSupplier;
class PlanetTerrainGenerator {
@ -43,7 +42,7 @@ class PlanetTerrainGenerator {
public PlanetTerrainGenerator(
PlanetGenerator generator,
SurfaceFloatField heightMap,
FloatRangeMap<TerrainLayer> layers
TerrainSupplier terrain
) {
this.parent = generator;
@ -53,7 +52,7 @@ class PlanetTerrainGenerator {
face -> new SurfaceTerrainGenerator(
new Surface(face, seaLevel),
heightMap,
layers
terrain
)
);
}
@ -86,6 +85,11 @@ class PlanetTerrainGenerator {
}
private void generateBorderTerrain(Server server, DefaultChunkData chunk) {
if (chunk.getPosition().x == 0 && chunk.getPosition().y == 0 && chunk.getPosition().z == 0) {
generateCore(server, chunk);
return;
}
BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone");
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
@ -109,4 +113,16 @@ class PlanetTerrainGenerator {
});
}
private void generateCore(Server server, DefaultChunkData chunk) {
BlockData tux = BlockDataRegistry.getInstance().get("Test:Tux");
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
GenericChunks.forEachBiC(bic -> {
chunk.setBlock(bic, air, false);
});
chunk.setBlock(new Vec3i(7, 7, 0), tux, false);
}
}

View File

@ -19,7 +19,6 @@ package ru.windcorp.progressia.server.world.generation.surface;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.block.BlockData;
@ -33,12 +32,12 @@ public class SurfaceTerrainGenerator {
private final Surface surface;
private final SurfaceFloatField heightMap;
private final FloatRangeMap<TerrainLayer> layers;
private final TerrainSupplier terrain;
public SurfaceTerrainGenerator(Surface surface, SurfaceFloatField heightMap, FloatRangeMap<TerrainLayer> layers) {
public SurfaceTerrainGenerator(Surface surface, SurfaceFloatField heightMap, TerrainSupplier terrain) {
this.surface = surface;
this.heightMap = heightMap;
this.layers = layers;
this.terrain = terrain;
}
public void generateTerrain(Server server, DefaultChunkData chunk) {
@ -74,7 +73,7 @@ public class SurfaceTerrainGenerator {
location.set(north, west, altitude);
SurfaceBlockContext blockContext = context.push(location);
BlockData block = layers.get(depth).get(blockContext, depth);
BlockData block = terrain.get(blockContext, depth);
blockContext.pop();

View File

@ -21,7 +21,7 @@ import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
@FunctionalInterface
public interface TerrainLayer {
public interface TerrainSupplier {
BlockData get(SurfaceBlockContext context, float depth);

View File

@ -0,0 +1,75 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.server.world.tasks;
import java.util.function.Consumer;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.server.Server;
class AddEntity extends CachedChange {
private EntityData entity;
public AddEntity(Consumer<? super CachedChange> disposer) {
super(disposer);
}
public void set(EntityData entity) {
if (this.entity != null)
throw new IllegalStateException("Entity is not null. Current: " + this.entity + "; requested: " + entity);
this.entity = entity;
}
@Override
public void affect(Server server) {
server.getWorld().spawnEntity(entity);
}
@Override
public void getRelevantChunk(Vec3i output) {
// Do nothing
}
@Override
public boolean isThreadSensitive() {
return false;
}
@Override
public void dispose() {
super.dispose();
this.entity = null;
}
@Override
public int hashCode() {
return System.identityHashCode(entity);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AddEntity))
return false;
return ((AddEntity) obj).entity == entity;
}
}

View File

@ -0,0 +1,75 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.server.world.tasks;
import java.util.function.Consumer;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.server.Server;
class RemoveEntity extends CachedChange {
private long entityId = EntityData.NULL_ENTITY_ID;
public RemoveEntity(Consumer<? super CachedChange> disposer) {
super(disposer);
}
public void set(long entityId) {
if (this.entityId != EntityData.NULL_ENTITY_ID)
throw new IllegalStateException("Entity ID is not null. Current: " + this.entityId + "; requested: " + entityId);
this.entityId = entityId;
}
@Override
public void affect(Server server) {
server.getWorld().getData().removeEntity(entityId);
}
@Override
public void getRelevantChunk(Vec3i output) {
// Do nothing
}
@Override
public boolean isThreadSensitive() {
return false;
}
@Override
public void dispose() {
super.dispose();
this.entityId = EntityData.NULL_ENTITY_ID;
}
@Override
public int hashCode() {
return Long.hashCode(entityId);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RemoveEntity))
return false;
return ((RemoveEntity) obj).entityId == entityId;
}
}

View File

@ -46,6 +46,9 @@ public class WorldAccessor implements ReportingServerContext.ChangeListener {
.addClass(SetBlock.class, () -> new SetBlock(disposer))
.addClass(AddTile.class, () -> new AddTile(disposer))
.addClass(RemoveTile.class, () -> new RemoveTile(disposer))
.addClass(AddEntity.class, () -> new AddEntity(disposer))
.addClass(RemoveEntity.class, () -> new RemoveEntity(disposer))
.addClass(ChangeEntity.class, () -> new ChangeEntity(disposer))
.addClass(BlockTriggeredUpdate.class, () -> new BlockTriggeredUpdate(disposer))
@ -81,14 +84,16 @@ public class WorldAccessor implements ReportingServerContext.ChangeListener {
@Override
public void onEntityAdded(EntityData entity) {
// TODO Auto-generated method stub
AddEntity change = cache.grab(AddEntity.class);
change.set(entity);
server.requestChange(change);
}
@Override
public void onEntityRemoved(long entityId) {
// TODO Auto-generated method stub
RemoveEntity change = cache.grab(RemoveEntity.class);
change.set(entityId);
server.requestChange(change);
}
@Override

View File

@ -50,7 +50,7 @@ public class LayerAbout extends GUILayer {
new Label(
"Version",
font,
new MutableStringLocalized("LayerAbout.Version").format("pre-alpha 2")
new MutableStringLocalized("LayerAbout.Version").format("pre-alpha 3")
)
);

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test;
import glm.vec._3.Vec3;
@ -129,7 +129,7 @@ public class LayerTestGUI extends GUILayer {
128
)
);
group.addChild(
new DynamicLabel(
"ChunkStatsDisplay",
@ -266,12 +266,21 @@ public class LayerTestGUI extends GUILayer {
}
private static final String[] CLOCK_CHARS = "\u2591\u2598\u259d\u2580\u2596\u258c\u259e\u259b\u2597\u259a\u2590\u259c\u2584\u2599\u259f\u2588"
.chars().mapToObj(c -> ((char) c) + "").toArray(String[]::new);
private static String getTPSClockChar() {
return CLOCK_CHARS[(int) (ServerState.getInstance().getUptimeTicks() % CLOCK_CHARS.length)];
}
private static final Averager FPS_RECORD = new Averager();
private static final Averager TPS_RECORD = new Averager();
private static final Supplier<CharSequence> TPS_STRING = DynamicStrings.builder()
.addDyn(new MutableStringLocalized("LayerTestGUI.TPSDisplay"))
.addDyn(() -> TPS_RECORD.update(ServerState.getInstance().getTPS()), 5, 1)
.add(' ')
.addDyn(LayerTestGUI::getTPSClockChar)
.buildSupplier();
private static final Supplier<CharSequence> POS_STRING = DynamicStrings.builder()

View File

@ -0,0 +1,51 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.server.world.block.BlockLogic;
import ru.windcorp.progressia.server.world.block.TickableBlock;
import ru.windcorp.progressia.server.world.context.ServerBlockContext;
import ru.windcorp.progressia.server.world.context.ServerBlockContextRO;
import ru.windcorp.progressia.server.world.ticking.TickingPolicy;
public class TestBlockLogicStatieSpawner extends BlockLogic implements TickableBlock {
public TestBlockLogicStatieSpawner(String id) {
super(id);
}
@Override
public void tick(ServerBlockContext context) {
Vec3i loc = context.toAbsolute(context.getLocation(), null);
EntityData entity = new TestEntityDataStatie();
entity.setPosition(new Vec3(loc.x, loc.y, loc.z));
context.addEntity(entity);
context.setBlock(BlockDataRegistry.getInstance().get("Test:Air"));
}
@Override
public TickingPolicy getTickingPolicy(ServerBlockContextRO context) {
return TickingPolicy.RANDOM;
}
}

View File

@ -0,0 +1,100 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test;
import glm.mat._4.Mat4;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.backend.Usage;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.client.graphics.model.Shape;
import ru.windcorp.progressia.client.graphics.model.ShapeParts;
import ru.windcorp.progressia.client.graphics.model.Shapes;
import ru.windcorp.progressia.client.graphics.model.StaticModel;
import ru.windcorp.progressia.client.graphics.texture.ComplexTexture;
import ru.windcorp.progressia.client.graphics.texture.SimpleTextures;
import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.world.block.BlockRender;
import ru.windcorp.progressia.common.world.DefaultChunkData;
public class TestBlockRenderTux extends BlockRender {
private final Renderable model;
public TestBlockRenderTux(String id) {
super(id);
TexturePrimitive primitive = SimpleTextures.get("blocks/Tux").getSprite().getPrimitive();
ComplexTexture texture = new ComplexTexture(primitive, 72, 60);
WorldRenderProgram program = WorldRenderProgram.getDefault();
StaticModel.Builder builder = StaticModel.builder();
final float scale = 1f / 40;
final float lift = -1f / 2 / scale;
builder.addPart(
new Shapes.PppBuilder(program, texture.getCuboidTextures(0, 36, 12)).setSize(12)
.centerAt(0, 0, 18 + (12 / 2) + lift).scale(scale).create()
);
builder.addPart(
new Shapes.PppBuilder(program, texture.getCuboidTextures(0, 0, 18)).setSize(18)
.centerAt(0, 0, 18 / 2 + lift).scale(scale).create()
);
builder.addPart(
new Shape(
Usage.STATIC,
program,
ShapeParts.createRectangle(
program,
texture.get(48, 44, 24, 16),
Colors.WHITE,
new Vec3(18 / 2 + 1, -(24 / 2), lift),
new Vec3(0, 24, 0),
new Vec3(0, 0, 16),
false
),
ShapeParts.createRectangle(
program,
texture.get(48, 44, 24, 16),
Colors.WHITE,
new Vec3(18 / 2 + 1, -(24 / 2), lift),
new Vec3(0, 24, 0),
new Vec3(0, 0, 16),
true
)
),
new Mat4().scale(scale)
);
this.model = builder.build();
}
@Override
public Renderable createRenderable(DefaultChunkData chunk, Vec3i relBlockInChunk) {
return model;
}
@Override
public boolean needsOwnRenderable() {
return true;
}
}

View File

@ -104,9 +104,10 @@ public class TestContent {
registerSimplestBlock("Dirt");
registerSimplestBlock("Chernozem");
registerSimplestBlock("Stone");
registerSimplestBlock("Mantle");
registerSimplestBlock("Water");
registerSimplestBlock("Brick");
registerSimplestBlock("BrickWhite");
registerSimplestBlock("Sand");
registerSimplestBlock("Concrete");
registerSimplestBlock("WoodenPlank");
@ -131,6 +132,14 @@ public class TestContent {
register(new BlockRenderTransparentCube("Test:TemporaryLeaves", getBlockTexture("TemporaryLeaves")));
// Sic, using Glass logic for leaves because Test
register(new TestBlockLogicGlass("Test:TemporaryLeaves"));
register(new BlockData("Test:StatieSpawner"));
register(new BlockRenderOpaqueCube("Test:StatieSpawner", getBlockTexture("StatieSpawner")));
register(new TestBlockLogicStatieSpawner("Test:StatieSpawner"));
register(new BlockData("Test:Tux"));
register(new TestBlockRenderTux("Test:Tux"));
register(new BlockLogic("Test:Tux"));
BlockDataRegistry.getInstance().values().forEach(PLACEABLE_BLOCKS::add);
PLACEABLE_BLOCKS.removeIf(b -> placeableBlacklist.contains(b.getId()));
@ -185,7 +194,6 @@ public class TestContent {
});
registerSimplestTransparentTile("Stones");
registerSimplestTransparentTile("Sand");
registerSimplestOpaqueTile("SnowOpaque");
Arrays.asList(

View File

@ -15,29 +15,41 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.progressia.client.graphics.model.Shapes;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.client.graphics.model.Shapes.PppBuilder;
import ru.windcorp.progressia.client.graphics.texture.ComplexTexture;
import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.world.entity.EntityRender;
import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry;
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
import ru.windcorp.progressia.common.world.entity.EntityData;
public class TestEntityRenderStatie extends EntityRender {
private final Renderable cube = new Shapes.PppBuilder(
WorldRenderProgram.getDefault(),
(Texture) null
)
.setColorMultiplier(1, 1, 0)
.create();
private final static int PARTICLE_COUNT = 16;
private final Renderable core;
private final Renderable particle;
public TestEntityRenderStatie(String id) {
super(id);
TexturePrimitive texturePrimitive = EntityRenderRegistry.getEntityTexture("Statie");
ComplexTexture texture = new ComplexTexture(texturePrimitive, 4, 4);
WorldRenderProgram program = WorldRenderProgram.getDefault();
final float coreSize = 1f / 4;
final float particleSize = 1f / 16;
core = new PppBuilder(program, texture.getCuboidTextures(0, 2, 1)).setSize(coreSize).centerAt(0, 0, 0).create();
particle = new PppBuilder(program, texture.getCuboidTextures(0, 0, 1)).setSize(particleSize)
.centerAt(2.5f * coreSize, 0, 0).create();
}
@Override
@ -45,11 +57,28 @@ public class TestEntityRenderStatie extends EntityRender {
return new EntityRenderable(entity) {
@Override
public void doRender(ShapeRenderHelper renderer) {
double phase = GraphicsInterface.getTime();
renderer.pushTransform().translate(0, 0, (float) Math.sin(phase) * 0.1f);
renderer.pushTransform().scale(
((TestEntityDataStatie) entity).getSize() / 24.0f
);
).rotateY((float) -Math.sin(phase - Math.PI / 3) * Math.PI / 12);
cube.render(renderer);
core.render(renderer);
renderer.popTransform();
renderer.popTransform();
renderer.pushTransform().translate(0, 0, (float) Math.sin(phase + Math.PI / 2) * 0.05f);
for (int i = 0; i < PARTICLE_COUNT; ++i) {
double phaseOffset = 2 * Math.PI / PARTICLE_COUNT * i;
renderer.pushTransform()
.translate((float) Math.sin(phase + phaseOffset) * 0.1f, 0, 0)
.rotateX(Math.sin(phase / 2 + phaseOffset) * Math.PI / 6)
.rotateZ(phase + phaseOffset * 2);
particle.render(renderer);
renderer.popTransform();
}
renderer.popTransform();
}

View File

@ -24,21 +24,18 @@ import java.util.List;
import java.util.function.Function;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.util.ArrayFloatRangeMap;
import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.util.noise.discrete.WorleyProceduralNoise;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.generation.WorldGenerator;
import ru.windcorp.progressia.server.world.generation.planet.Planet;
import ru.windcorp.progressia.server.world.generation.planet.PlanetGenerator;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer;
import ru.windcorp.progressia.test.Rocks.RockVariant;
import ru.windcorp.progressia.test.Rocks.Rock;
import ru.windcorp.progressia.test.TestContent;
import ru.windcorp.progressia.test.gen.feature.*;
import ru.windcorp.progressia.test.gen.terrain.*;
public class TestGenerationConfig {
@ -71,47 +68,45 @@ public class TestGenerationConfig {
TestHeightMap heightMap = new TestHeightMap(planet, planet.getRadius() / 4, fields);
FloatRangeMap<TerrainLayer> layers = new ArrayFloatRangeMap<>();
registerTerrainLayers(layers);
LayeredTerrain terrain = new LayeredTerrain();
registerTerrainLayers(terrain);
List<SurfaceFeature> features = new ArrayList<>();
registerFeatures(features);
return server -> new PlanetGenerator("Test:PlanetGenerator", server, planet, heightMap, layers, features);
return server -> new PlanetGenerator("Test:PlanetGenerator", server, planet, heightMap, terrain, features);
}
private void registerTerrainLayers(FloatRangeMap<TerrainLayer> layers) {
BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt");
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
private void registerTerrainLayers(LayeredTerrain terrain) {
SurfaceFloatField cliffs = fields.get("Test:Cliff");
SurfaceFloatField beaches = fields.register(
"Test:Beach",
f -> multiply(
anti(fields.get("Test:Cliff", f))
)
);
RockStrata rockStrata = createStrata();
WorleyProceduralNoise.Builder<TerrainLayer> builder = WorleyProceduralNoise.builder();
TestContent.ROCKS.getRocks().forEach(rock -> {
builder.add((c, d) -> {
if (c.getRandom().nextInt(3) == 0) {
return rock.getBlock(RockVariant.CRACKED);
} else {
return rock.getBlock(RockVariant.MONOLITH);
}
}, 1);
});
terrain.addLayer(new AirLayer("Test:Air"));
terrain.addLayer(new MantleLayer("Test:Mantle"));
terrain.addLayer(new CrustLayer("Test:Crust", rockStrata));
terrain.addLayer(new WaterLayer("Test:Water"));
terrain.addLayer(new SoilLayer("Test:Soil"));
terrain.addLayer(new CliffLayer("Test:Cliffs", cliffs, rockStrata));
terrain.addLayer(new BeachLayer("Test:Beaches", beaches, rockStrata));
}
private RockStrata createStrata() {
WorleyProceduralNoise.Builder<Rock> builder = WorleyProceduralNoise.builder();
TestContent.ROCKS.getRocks().forEach(rock -> builder.add(rock, 1));
SurfaceFloatField rockDepthOffsets = fields.register(
"Test:RockDepthOffsets",
() -> tweak(fields.primitive(), 40, 5)
);
RockLayer rockLayer = new RockLayer(builder.build(SEED), rockDepthOffsets);
layers.put(Float.NEGATIVE_INFINITY, 0, (c, d) -> air);
layers.put(0, 4, (c, d) -> {
if (cliffs.get(c.getSurface().getUp(), c.getLocation().x, c.getLocation().y) > 0) {
return rockLayer.get(c, d);
} else {
return dirt;
}
});
layers.put(4, Float.POSITIVE_INFINITY, rockLayer);
return new RockStrata(builder.build(SEED), rockDepthOffsets);
}
private void registerFeatures(List<SurfaceFeature> features) {

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen;
package ru.windcorp.progressia.test.gen.feature;
import java.util.Set;
import java.util.function.Consumer;

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen;
package ru.windcorp.progressia.test.gen.feature;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.block.BlockData;

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen;
package ru.windcorp.progressia.test.gen.feature;
import java.util.Set;
import java.util.function.Function;

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen;
package ru.windcorp.progressia.test.gen.feature;
import java.util.List;
import java.util.Set;
@ -67,7 +67,6 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
private final List<TileData> scatter = ImmutableList.of(
TileDataRegistry.getInstance().get("Test:Stones"),
TileDataRegistry.getInstance().get("Test:Sand"),
TileDataRegistry.getInstance().get("Test:Bush"),
TileDataRegistry.getInstance().get("Test:Fern")
);
@ -104,7 +103,17 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
}
private void growGrass(SurfaceBlockContext context, double grassiness) {
TileData flatGrass = flatGrasses.get((float) grassiness);
double flatGrassiness = grassiness;
BlockData soil = context.getBlock();
if (soil.getId().endsWith("Sand")) {
flatGrassiness = flatGrassiness / 2 - 0.2;
if (flatGrassiness < 0) {
flatGrassiness = 0;
}
}
TileData flatGrass = flatGrasses.get((float) flatGrassiness);
if (flatGrass != null) {
for (RelFace face : RelFace.getFaces()) {
if (face == RelFace.DOWN)

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen;
package ru.windcorp.progressia.test.gen.feature;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.block.BlockData;

View File

@ -0,0 +1,42 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
public class AirLayer extends TerrainLayer {
private final BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
public AirLayer(String id) {
super(id);
}
@Override
public BlockData generate(SurfaceBlockContext context, float depth, float intensity) {
return air;
}
@Override
public float getIntensity(SurfaceBlockContext context, float depth) {
return depth <= 0 ? 1 : 0;
}
}

View File

@ -0,0 +1,55 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
import ru.windcorp.progressia.test.Rocks.RockVariant;
public class BeachLayer extends TerrainLayer {
private final SurfaceFloatField beachSelector;
private final RockStrata strata;
public BeachLayer(String id, SurfaceFloatField beachSelector, RockStrata strata) {
super(id);
this.beachSelector = beachSelector;
this.strata = strata;
}
@Override
public BlockData generate(SurfaceBlockContext context, float depth, float intensity) {
return strata.get(context, depth).getBlock(RockVariant.SAND);
}
@Override
public float getIntensity(SurfaceBlockContext context, float depth) {
if (depth < 0 || depth > 3) {
return 0;
}
float altitude = context.getLocation().z;
if (altitude < -5| altitude > 1) {
return 0;
}
return 3 * beachSelector.get(context);
}
}

View File

@ -0,0 +1,64 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
import ru.windcorp.progressia.test.Rocks.RockVariant;
public class CliffLayer extends TerrainLayer {
private final SurfaceFloatField cliffSelector;
private final RockStrata strata;
public CliffLayer(String id, SurfaceFloatField cliffSelector, RockStrata strata) {
super(id);
this.cliffSelector = cliffSelector;
this.strata = strata;
}
@Override
public BlockData generate(SurfaceBlockContext context, float depth, float intensity) {
RockVariant variant;
switch (context.getRandom().nextInt(4)) {
case 0:
variant = RockVariant.GRAVEL;
break;
case 1:
variant = RockVariant.MONOLITH;
break;
default:
variant = RockVariant.CRACKED;
break;
}
return strata.get(context, depth).getBlock(variant);
}
@Override
public float getIntensity(SurfaceBlockContext context, float depth) {
if (depth < 0 || depth > 7) {
return 0;
}
return 100 * cliffSelector.get(context);
}
}

View File

@ -0,0 +1,69 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.util.ArrayFloatRangeMap;
import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
import ru.windcorp.progressia.test.Rocks.RockVariant;
public class CrustLayer extends TerrainLayer {
private static final FloatRangeMap<RockVariant> WEAR_TABLE = new ArrayFloatRangeMap<>();
static {
WEAR_TABLE.put(Float.NEGATIVE_INFINITY, 0.25f, RockVariant.MONOLITH);
WEAR_TABLE.put(0.25f, 0.5f, RockVariant.CRACKED);
WEAR_TABLE.put(0.5f, 0.75f, RockVariant.GRAVEL);
WEAR_TABLE.put(0.75f, Float.POSITIVE_INFINITY, RockVariant.SAND);
}
private final RockStrata strata;
public CrustLayer(String id, RockStrata strata) {
super(id);
this.strata = strata;
}
@Override
public BlockData generate(SurfaceBlockContext context, float depth, float intensity) {
RockVariant variant;
if (depth < 8) {
float wear = 1 - depth / 8;
float offset = (context.getRandom().nextFloat() * 2 - 1) * 0.5f;
variant = WEAR_TABLE.get(wear + offset);
} else {
variant = RockVariant.MONOLITH;
}
return strata.get(context, depth).getBlock(variant);
}
@Override
public float getIntensity(SurfaceBlockContext context, float depth) {
if (depth < 0) {
return 0;
} else if (context.getLocation().z > -100) {
return 1;
} else {
return 0;
}
}
}

View File

@ -0,0 +1,61 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import java.util.ArrayList;
import java.util.List;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.server.world.generation.surface.TerrainSupplier;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
public class LayeredTerrain implements TerrainSupplier {
private final List<TerrainLayer> layers = new ArrayList<>();
public void addLayer(TerrainLayer layer) {
this.layers.add(layer);
}
@Override
public BlockData get(SurfaceBlockContext context, float depth) {
TerrainLayer layer = null;
float intensity = 0;
for (int i = 0; i < layers.size(); ++i) {
TerrainLayer currentLayer = layers.get(i);
float currentIntensity = currentLayer.getIntensity(context, depth);
if (currentIntensity <= 0) {
continue;
}
if (intensity < currentIntensity) {
intensity = currentIntensity;
layer = currentLayer;
}
}
if (layer == null) {
layer = layers.get(0);
}
return layer.generate(context, depth, intensity);
}
}

View File

@ -0,0 +1,42 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
public class MantleLayer extends TerrainLayer {
private final BlockData material = BlockDataRegistry.getInstance().get("Test:Mantle");
public MantleLayer(String id) {
super(id);
}
@Override
public BlockData generate(SurfaceBlockContext context, float depth, float intensity) {
return material;
}
@Override
public float getIntensity(SurfaceBlockContext context, float depth) {
return context.getLocation().z <= -100 ? 1 : 0;
}
}

View File

@ -15,43 +15,38 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen;
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.util.noise.discrete.DiscreteNoise;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
import ru.windcorp.progressia.test.Rocks.Rock;
public class RockLayer implements TerrainLayer {
private final DiscreteNoise<TerrainLayer> strata;
public class RockStrata {
private final DiscreteNoise<Rock> distribution;
private final SurfaceFloatField depthOffsets;
private final double horizontalScale = 200;
private final double verticalScale = 10;
private final double depthInfluense = 0.1;
private final double horizontalScale = 800;
private final double verticalScale = 20;
private final double depthInfluence = 0.1;
public RockLayer(DiscreteNoise<TerrainLayer> strata, SurfaceFloatField depthOffsets) {
this.strata = strata;
public RockStrata(DiscreteNoise<Rock> distribution, SurfaceFloatField depthOffsets) {
this.distribution = distribution;
this.depthOffsets = depthOffsets;
}
@Override
public BlockData get(SurfaceBlockContext context, float depth) {
public Rock get(SurfaceBlockContext context, float depth) {
double z = context.getLocation().z;
z -= depth * depthInfluense;
z -= depth * depthInfluence;
z += depthOffsets.get(context);
z /= verticalScale;
return strata
.get(
return distribution.get(
context.getLocation().x / horizontalScale,
context.getLocation().y / horizontalScale,
z
)
.get(context, depth);
);
}
}

View File

@ -0,0 +1,59 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.util.math.PiecewiseLinearFunction;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
public class SoilLayer extends TerrainLayer {
private static final PiecewiseLinearFunction THICKNESS = PiecewiseLinearFunction.builder()
.add(Units.get("-5 m"), Units.get("1 m"))
.add(Units.get("0 m"), Units.get("4 m"))
.add(Units.get("5 km"), Units.get("0 m"))
.build();
private final BlockData soil = BlockDataRegistry.getInstance().get("Test:Dirt");
public SoilLayer(String id) {
super(id);
}
@Override
public BlockData generate(SurfaceBlockContext context, float depth, float intensity) {
return soil;
}
@Override
public float getIntensity(SurfaceBlockContext context, float depth) {
if (depth < 0) return 0;
float altitude = context.getLocation().z;
float thickness = THICKNESS.apply(altitude);
if (depth < thickness) {
return 2;
} else {
return 0;
}
}
}

View File

@ -0,0 +1,34 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
public abstract class TerrainLayer extends Namespaced {
public TerrainLayer(String id) {
super(id);
}
public abstract BlockData generate(SurfaceBlockContext context, float depth, float intensity);
public abstract float getIntensity(SurfaceBlockContext context, float depth);
}

View File

@ -0,0 +1,45 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen.terrain;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
public class WaterLayer extends TerrainLayer {
private final BlockData water = BlockDataRegistry.getInstance().get("Test:Water");
public WaterLayer(String id) {
super(id);
}
@Override
public BlockData generate(SurfaceBlockContext context, float depth, float intensity) {
return water;
}
@Override
public float getIntensity(SurfaceBlockContext context, float depth) {
if (depth <= 0 && context.getLocation().z <= 0) {
return 2;
}
return 0;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB