diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
index af3136e5b..1c4133bbe 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
@@ -25,8 +25,7 @@ import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
-import com.seibel.distanthorizons.core.util.objects.GLMessage;
-import com.seibel.distanthorizons.core.util.objects.GLMessageOutputStream;
+import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.apache.logging.log4j.LogManager;
@@ -38,28 +37,17 @@ import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.opengl.GLUtil;
import java.io.PrintStream;
-import java.lang.invoke.MethodHandles;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* A singleton that holds references to different openGL contexts
* and GPU capabilities.
- *
- *
- * Helpful OpenGL resources:
- *
- * https://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf
- * https://learnopengl.com/Advanced-OpenGL/Advanced-Data
- * https://www.slideshare.net/CassEveritt/approaching-zero-driver-overhead
- *
- * https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one
- * https://stackoverflow.com/questions/63509735/massive-performance-loss-with-glmapbuffer
*/
public class GLProxy
{
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
- private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
+ private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final ConfigBasedLogger GL_LOGGER = new ConfigBasedLogger(LogManager.getLogger(GLProxy.class),
() -> Config.Common.Logging.logRendererGLEvent.get());
@@ -79,7 +67,29 @@ public class GLProxy
private final EDhApiGpuUploadMethod preferredUploadMethod;
- public final GLMessage.Builder vanillaDebugMessageBuilder = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER;
+ public final GLMessageBuilder vanillaDebugMessageBuilder =
+ new GLMessageBuilder(
+ (type) ->
+ {
+ if (type == EGLMessageType.POP_GROUP)
+ return false;
+ else if (type == EGLMessageType.PUSH_GROUP)
+ return false;
+ else if (type == EGLMessageType.MARKER)
+ return false;
+ else
+ return true;
+ },
+ (severity) ->
+ {
+ // notifications can generally be ignored (if they are logged at all)
+ if (severity == EGLMessageSeverity.NOTIFICATION)
+ return false;
+ else
+ return true;
+ },
+ null
+ );
@@ -268,11 +278,11 @@ public class GLProxy
- if (msg.type == GLMessage.EType.ERROR || msg.type == GLMessage.EType.UNDEFINED_BEHAVIOR)
+ if (msg.type == EGLMessageType.ERROR || msg.type == EGLMessageType.UNDEFINED_BEHAVIOR)
{
// critical error
- GL_LOGGER.error("GL ERROR " + msg.id + " from " + msg.source + ": " + msg.message);
+ GL_LOGGER.error("GL ERROR [" + msg.id + "] from [" + msg.source + "]: [" + msg.message + "].");
if (errorHandlingMode == EDhApiGLErrorHandlingMode.LOG_THROW)
{
@@ -284,28 +294,28 @@ public class GLProxy
{
// non-critical log
- GLMessage.ESeverity severity = msg.severity;
- RuntimeException ex = new RuntimeException("GL MESSAGE: " + msg);
+ EGLMessageSeverity severity = msg.severity;
+ RuntimeException exception = new RuntimeException("GL MESSAGE: " + msg);
if (severity == null)
{
// just in case the message was malformed
- severity = GLMessage.ESeverity.LOW;
+ severity = EGLMessageSeverity.LOW;
}
switch (severity)
{
case HIGH:
- GL_LOGGER.error("{}", ex);
+ GL_LOGGER.error(exception.getMessage(), exception);
break;
case MEDIUM:
- GL_LOGGER.warn("{}", ex);
+ GL_LOGGER.warn(exception.getMessage(), exception);
break;
case LOW:
- GL_LOGGER.info("{}", ex);
+ GL_LOGGER.info(exception.getMessage(), exception);
break;
case NOTIFICATION:
- GL_LOGGER.debug("{}", ex);
+ GL_LOGGER.debug(exception.getMessage(), exception);
break;
}
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessage.java
deleted file mode 100644
index 8fc852339..000000000
--- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessage.java
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020 James Seibel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, version 3.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.seibel.distanthorizons.core.util.objects;
-
-import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
-import com.seibel.distanthorizons.coreapi.ModInfo;
-import org.apache.logging.log4j.Logger;
-
-import java.lang.invoke.MethodHandles;
-import java.util.HashMap;
-import java.util.function.Function;
-
-/**
- * Handles parsing and creating string messages from OpenGL messages.
- *
- * @author Leetom
- * @version 2022-10-1
- */
-public final class GLMessage
-{
- private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
-
- static final String HEADER = "[LWJGL] OpenGL debug message";
- public final EType type;
- public final ESeverity severity;
- public final ESource source;
- public final String id;
- public final String message;
-
- /** This is needed since gl callback will not have the correct class loader set, which causes issues. */
- static void initLoadClass()
- {
- Builder dummy = new Builder();
- dummy.add(GLMessage.HEADER);
- dummy.add("ID");
- dummy.add(":");
- dummy.add("dummyId");
- dummy.add("Source");
- dummy.add(":");
- dummy.add(ESource.API.name);
- dummy.add("Type");
- dummy.add(":");
- dummy.add(EType.OTHER.name);
- dummy.add("Severity");
- dummy.add(":");
- dummy.add(ESeverity.LOW.name);
- dummy.add("Message");
- dummy.add(":");
- dummy.add("dummyMessage");
- }
-
- static
- {
- initLoadClass();
- }
-
-
-
- GLMessage(EType type, ESeverity severity, ESource source, String id, String message)
- {
- this.type = type;
- this.source = source;
- this.severity = severity;
- this.id = id;
- this.message = message;
- }
-
- @Override
- public String toString() { return "[level:" + severity + ", type:" + type + ", source:" + source + ", id:" + id + ", msg:{" + message + "}]"; }
-
-
-
- //==============//
- // helper enums //
- //==============//
-
- public enum EType
- {
- ERROR,
- DEPRECATED_BEHAVIOR,
- UNDEFINED_BEHAVIOR,
- PORTABILITY,
- PERFORMANCE,
- MARKER,
- PUSH_GROUP,
- POP_GROUP,
- OTHER;
-
-
- private static final HashMap ENUM_BY_NAME = new HashMap<>();
-
- private final String name;
-
-
- static
- {
- for (EType type : EType.values())
- {
- ENUM_BY_NAME.put(type.name, type);
- }
- }
-
- EType() { name = super.toString().toUpperCase(); }
-
-
- @Override
- public final String toString() { return name; }
-
- public static EType get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
-
- }
-
- public enum ESource
- {
- API,
- WINDOW_SYSTEM,
- SHADER_COMPILER,
- THIRD_PARTY,
- APPLICATION,
- OTHER;
-
-
- private static final HashMap ENUM_BY_NAME = new HashMap<>();
-
- public final String name;
-
-
- static
- {
- for (ESource source : ESource.values())
- {
- ENUM_BY_NAME.put(source.name, source);
- }
- }
-
- ESource() { name = super.toString().toUpperCase(); }
-
-
- @Override
- public final String toString() { return name; }
-
- public static ESource get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
-
- }
-
- public enum ESeverity
- {
- HIGH,
- MEDIUM,
- LOW,
- NOTIFICATION;
-
-
- public final String name;
-
- static final HashMap ENUM_BY_NAME = new HashMap<>();
-
-
- static
- {
- for (ESeverity severity : ESeverity.values())
- {
- ENUM_BY_NAME.put(severity.name, severity);
- }
- }
-
- ESeverity() { name = super.toString().toUpperCase(); }
-
-
- @Override
- public final String toString() { return name; }
-
- public static ESeverity get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
-
- }
-
-
-
- //================//
- // helper classes //
- //================//
-
- /**
- * Expected message format:
- *
- * [LWJGL] OpenGL debug message
- * ID: 0x20071
- * Source: API
- * Type: OTHER
- * Severity: NOTIFICATION
- * Message: Buffer detailed info: Buffer object 1014084 (bound to ...
- *
- */
- public static class Builder
- {
- /** how many stages are present in the message parser */
- private static final int FINAL_PARSER_STAGE_INDEX = 15;
-
- public static final Builder DEFAULT_MESSAGE_BUILDER =
- new Builder(
- (type) ->
- { // type filter
- if (type == GLMessage.EType.POP_GROUP)
- return false;
- if (type == GLMessage.EType.PUSH_GROUP)
- return false;
- if (type == GLMessage.EType.MARKER)
- return false;
- // if (type == GLMessage.Type.PERFORMANCE) return false;
- return true;
- },
- (severity) ->
- { // severity filter
- if (severity == GLMessage.ESeverity.NOTIFICATION)
- return false;
- return true;
- },
- null
- );
-
-
- private final StringBuilder inProgressMessageBuilder = new StringBuilder();
-
- private EType type;
- private ESeverity severity;
- private ESource source;
-
- /** if the function returns false the message will be allowed */
- private final Function typeFilter;
- /** if the function returns false the message will be allowed */
- private final Function severityFilter;
- /** if the function returns false the message will be allowed */
- private final Function sourceFilter;
-
- private String id;
- private String message;
- /** how far into the message parser this builder is */
- private int parserStage = 0;
-
-
-
- static
- {
- initLoadClass();
- }
-
- public Builder() { this(null, null, null); }
-
- public Builder(
- Function typeFilter,
- Function severityFilter,
- Function sourceFilter)
- {
- this.typeFilter = typeFilter;
- this.severityFilter = severityFilter;
- this.sourceFilter = sourceFilter;
- }
-
-
-
- /**
- * Adds the given string to the message builder.
- *
- * Will log a warning if the string given wasn't expected
- * for the next stage of the OpenGL message format.
- *
- * @return null if the message isn't complete
- */
- public GLMessage add(String str)
- {
- // TODO fix implementation for MC 1.20.2 and newer
- // please see the incomplete GLMessageTest for an example as to how the message formats differ
- if (true)
- return null;
-
- str = str.trim();
- if (str.isEmpty())
- return null;
-
- boolean parseSuccess = runNextParserStage(str);
- if (parseSuccess && parserStage > FINAL_PARSER_STAGE_INDEX)
- {
- this.parserStage = 0;
- GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
- if (doesMessagePassFilters(msg))
- {
- return msg;
- }
- }
- else if (!parseSuccess)
- {
- LOGGER.warn("Failed to parse GLMessage line '{}' at stage {}", str, parserStage);
- }
-
- // the message isn't finished yet
- return null;
-
- // TODO implement a method that works for both MC 1.20.2+ and 1.20.1-
- //if (str.equals(HEADER) && inProgressMessageBuilder.length() != 0)
- //{
- // boolean parseSuccess = runNextParserStage(str);
- // if (parseSuccess && parserStage > FINAL_PARSER_STAGE_INDEX)
- // {
- // this.parserStage = 0;
- // GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
- // if (doesMessagePassFilters(msg))
- // {
- // return msg;
- // }
- // else
- // {
- // inProgressMessageBuilder.setLength(0);
- // return null;
- // }
- // }
- // else
- // {
- // if (!parseSuccess)
- // {
- // LOGGER.warn("Failed to parse GLMessage line '{}' at stage {}", str, parserStage);
- // inProgressMessageBuilder.setLength(0);
- // }
- //
- // return null;
- // }
- //}
- //else
- //{
- // inProgressMessageBuilder.append(str);
- // return null;
- //}
- }
-
- private boolean doesMessagePassFilters(GLMessage msg)
- {
- if (this.sourceFilter != null && !this.sourceFilter.apply(msg.source))
- return false;
- else if (this.typeFilter != null && !this.typeFilter.apply(msg.type))
- return false;
- else if (this.severityFilter != null && !this.severityFilter.apply(msg.severity))
- return false;
- else
- return true;
- }
-
- /** @return true if the given string was expected next for the OpenGL message format */
- private boolean runNextParserStage(String str)
- {
- switch (this.parserStage)
- {
- case 0:
- return checkAndIncStage(str, GLMessage.HEADER);
- case 1:
- return checkAndIncStage(str, "ID");
- case 2:
- return checkAndIncStage(str, ":");
- case 3:
- this.id = str;
- this.parserStage++;
- return true;
- case 4:
- return checkAndIncStage(str, "Source");
- case 5:
- return checkAndIncStage(str, ":");
- case 6:
- this.source = ESource.get(str);
- this.parserStage++;
- return true;
- case 7:
- return checkAndIncStage(str, "Type");
- case 8:
- return checkAndIncStage(str, ":");
- case 9:
- this.type = EType.get(str);
- this.parserStage++;
- return true;
- case 10:
- return checkAndIncStage(str, "Severity");
- case 11:
- return checkAndIncStage(str, ":");
- case 12:
- this.severity = ESeverity.get(str);
- this.parserStage++;
- return true;
- case 13:
- return checkAndIncStage(str, "Message");
- case 14:
- return checkAndIncStage(str, ":");
- case 15:
- this.message = str;
- this.parserStage++;
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Returns true and increments the parserStage
- * if the given and expected strings are the same.
- */
- private boolean checkAndIncStage(String givenString, String expectedString)
- {
- boolean equal = givenString.equals(expectedString);
- //boolean equal = givenString.contains(expectedString);
- if (equal)
- this.parserStage++;
- return equal;
- }
-
- } // builder class
-
-}
\ No newline at end of file
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageSeverity.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageSeverity.java
new file mode 100644
index 000000000..959e51223
--- /dev/null
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageSeverity.java
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.distanthorizons.core.util.objects.GLMessages;
+
+import java.util.HashMap;
+
+public enum EGLMessageSeverity
+{
+ HIGH,
+ MEDIUM,
+ LOW,
+ NOTIFICATION;
+
+
+ public final String name;
+
+ static final HashMap ENUM_BY_NAME = new HashMap<>();
+
+
+ static
+ {
+ for (EGLMessageSeverity severity : EGLMessageSeverity.values())
+ {
+ ENUM_BY_NAME.put(severity.name, severity);
+ }
+ }
+
+ EGLMessageSeverity() { this.name = super.toString().toUpperCase(); }
+
+
+ @Override
+ public final String toString() { return this.name; }
+
+ public static EGLMessageSeverity get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
+
+}
+
\ No newline at end of file
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageSource.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageSource.java
new file mode 100644
index 000000000..119204026
--- /dev/null
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageSource.java
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.distanthorizons.core.util.objects.GLMessages;
+
+import java.util.HashMap;
+
+public enum EGLMessageSource
+{
+ API,
+ WINDOW_SYSTEM,
+ SHADER_COMPILER,
+ THIRD_PARTY,
+ APPLICATION,
+ OTHER;
+
+
+ private static final HashMap ENUM_BY_NAME = new HashMap<>();
+
+ public final String name;
+
+
+ static
+ {
+ for (EGLMessageSource source : EGLMessageSource.values())
+ {
+ ENUM_BY_NAME.put(source.name, source);
+ }
+ }
+
+ EGLMessageSource() { this.name = super.toString().toUpperCase(); }
+
+
+ @Override
+ public final String toString() { return this.name; }
+
+ public static EGLMessageSource get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
+
+}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageType.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageType.java
new file mode 100644
index 000000000..8ae4f9ef8
--- /dev/null
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/EGLMessageType.java
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.distanthorizons.core.util.objects.GLMessages;
+
+import java.util.HashMap;
+
+public enum EGLMessageType
+{
+ ERROR,
+ DEPRECATED_BEHAVIOR,
+ UNDEFINED_BEHAVIOR,
+ PORTABILITY,
+ PERFORMANCE,
+ MARKER,
+ PUSH_GROUP,
+ POP_GROUP,
+ OTHER;
+
+
+ private static final HashMap ENUM_BY_NAME = new HashMap<>();
+
+ public final String name;
+
+
+ static
+ {
+ for (EGLMessageType type : EGLMessageType.values())
+ {
+ ENUM_BY_NAME.put(type.name, type);
+ }
+ }
+
+ EGLMessageType() { this.name = super.toString().toUpperCase(); }
+
+
+ @Override
+ public final String toString() { return this.name; }
+
+ public static EGLMessageType get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
+
+}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessage.java
new file mode 100644
index 000000000..0e7afcb15
--- /dev/null
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessage.java
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.distanthorizons.core.util.objects.GLMessages;
+
+public final class GLMessage
+{
+ static final String HEADER = "[LWJGL] OpenGL debug message";
+ public final EGLMessageType type;
+ public final EGLMessageSeverity severity;
+ public final EGLMessageSource source;
+ public final String id;
+ public final String message;
+
+
+
+ GLMessage(EGLMessageType type, EGLMessageSeverity severity, EGLMessageSource source, String id, String message)
+ {
+ this.type = type;
+ this.source = source;
+ this.severity = severity;
+ this.id = id;
+ this.message = message;
+ }
+
+
+
+ @Override
+ public String toString()
+ {
+ return "level: [" + this.severity + "], " +
+ "type: [" + this.type + "], " +
+ "source: [" + this.source + "], " +
+ "id: [" + this.id + "], " +
+ "msg: [" + this.message + "]";
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessageBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessageBuilder.java
new file mode 100644
index 000000000..8c775a818
--- /dev/null
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessageBuilder.java
@@ -0,0 +1,319 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.distanthorizons.core.util.objects.GLMessages;
+
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import org.apache.logging.log4j.Logger;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/** Expected message formats can be found in GLMessageTest. */
+public class GLMessageBuilder
+{
+ private static final Logger LOGGER = DhLoggerBuilder.getLogger();
+
+ /** how many stages are present in the message parser */
+ private static final int FINAL_LEGACY_PARSER_STAGE_INDEX = 15;
+ private static final int FINAL_NEW_PARSER_STAGE_INDEX = 5;
+
+
+
+ private EGLMessageType type;
+ private EGLMessageSeverity severity;
+ private EGLMessageSource source;
+
+ /** if the function returns false the message will be allowed */
+ private final Function typeFilter;
+ /** if the function returns false the message will be allowed */
+ private final Function severityFilter;
+ /** if the function returns false the message will be allowed */
+ private final Function sourceFilter;
+
+ private String id;
+ private String message;
+ /** how far into the message parser this builder is */
+ private int parserStage = 0;
+
+ private boolean legacyMessage = true;
+
+
+
+ //==============//
+ // constructors //
+ //==============//
+
+ public GLMessageBuilder() { this(null, null, null); }
+
+ public GLMessageBuilder(
+ Function typeFilter,
+ Function severityFilter,
+ Function sourceFilter)
+ {
+ this.typeFilter = typeFilter;
+ this.severityFilter = severityFilter;
+ this.sourceFilter = sourceFilter;
+ }
+
+
+
+ //=================//
+ // message parsing //
+ //=================//
+
+ /**
+ * Adds the given string to the message builder.
+ *
+ * Will log a warning if the string given wasn't expected
+ * for the next stage of the OpenGL message format.
+ *
+ * @return null if the message isn't complete
+ */
+ public GLMessage add(String str)
+ {
+ str = str.trim();
+ if (str.isEmpty())
+ {
+ return null;
+ }
+
+ boolean messageFinished = false;
+ boolean parseSuccess = this.runNextParserStage(str);
+
+
+ if (this.legacyMessage
+ && this.parserStage > FINAL_LEGACY_PARSER_STAGE_INDEX)
+ {
+ messageFinished = true;
+ }
+ else if (!this.legacyMessage
+ && this.parserStage > FINAL_NEW_PARSER_STAGE_INDEX)
+ {
+ messageFinished = true;
+ }
+
+
+ if (parseSuccess && messageFinished)
+ {
+ this.parserStage = 0;
+ GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
+ if (this.doesMessagePassFilters(msg))
+ {
+ return msg;
+ }
+ }
+ else if (!parseSuccess && messageFinished)
+ {
+ LOGGER.warn("Failed to parse GLMessage line [" + str + "] at stage [" + this.parserStage + "]");
+ }
+
+ // the message isn't finished yet
+ return null;
+ }
+
+ private boolean doesMessagePassFilters(GLMessage msg)
+ {
+ if (this.sourceFilter != null && !this.sourceFilter.apply(msg.source))
+ return false;
+ else if (this.typeFilter != null && !this.typeFilter.apply(msg.type))
+ return false;
+ else if (this.severityFilter != null && !this.severityFilter.apply(msg.severity))
+ return false;
+ else
+ return true;
+ }
+
+ /** @return true if the given string was expected next for the OpenGL message format */
+ private boolean runNextParserStage(String str)
+ {
+ if (this.parserStage == 0)
+ {
+ return this.checkExactAndIncStage(str, GLMessage.HEADER);
+ }
+ else if (this.parserStage == 1)
+ {
+ // legacy message only contains "ID" (not the colon)
+ this.legacyMessage = !str.contains("ID: ");
+ }
+
+
+ if (this.legacyMessage)
+ {
+ return this.runNextLegacyParserStage(str);
+ }
+ else
+ {
+ return this.runNextNewParserStage(str);
+ }
+ }
+ /** MC 1.20.2 and older */
+ private boolean runNextLegacyParserStage(String str)
+ {
+ switch (this.parserStage)
+ {
+ case 0:
+ throw new IllegalStateException("Parser should be past stage ["+this.parserStage+"], next stage is [1].");
+ case 1:
+ return this.checkExactAndIncStage(str, "ID");
+ case 2:
+ return this.checkExactAndIncStage(str, ":");
+ case 3:
+ this.id = str;
+ this.parserStage++;
+ return true;
+ case 4:
+ return this.checkExactAndIncStage(str, "Source");
+ case 5:
+ return this.checkExactAndIncStage(str, ":");
+ case 6:
+ this.source = EGLMessageSource.get(str);
+ this.parserStage++;
+ return true;
+ case 7:
+ return this.checkExactAndIncStage(str, "Type");
+ case 8:
+ return this.checkExactAndIncStage(str, ":");
+ case 9:
+ this.type = EGLMessageType.get(str);
+ this.parserStage++;
+ return true;
+ case 10:
+ return this.checkExactAndIncStage(str, "Severity");
+ case 11:
+ return this.checkExactAndIncStage(str, ":");
+ case 12:
+ this.severity = EGLMessageSeverity.get(str);
+ this.parserStage++;
+ return true;
+ case 13:
+ return this.checkExactAndIncStage(str, "Message");
+ case 14:
+ return this.checkExactAndIncStage(str, ":");
+ case 15:
+ this.message = str;
+ this.parserStage++;
+ return true;
+ default:
+ return false;
+ }
+ }
+ /** after MC 1.20.2 */
+ private boolean runNextNewParserStage(String str)
+ {
+ switch (this.parserStage)
+ {
+ case 0:
+ throw new IllegalStateException("Parser should be past stage [" + this.parserStage + "], next stage is [1].");
+ case 1:
+ String idPrefix = "ID: ";
+ return this.checkPrefixAndRun(str, idPrefix,
+ (line) ->
+ {
+ this.id = trySubstring(str, idPrefix.length());
+ this.parserStage++;
+ });
+ case 2:
+ String sourcePrefix = "Source: ";
+ return this.checkPrefixAndRun(str, sourcePrefix,
+ (line) ->
+ {
+ String sourceString = trySubstring(str, sourcePrefix.length());
+ this.source = EGLMessageSource.get(sourceString);
+ this.parserStage++;
+ });
+ case 3:
+ String typePrefix = "Type: ";
+ return this.checkPrefixAndRun(str, typePrefix,
+ (line) ->
+ {
+ String sourceString = trySubstring(str, typePrefix.length());
+ this.type = EGLMessageType.get(sourceString);
+ this.parserStage++;
+ });
+ case 4:
+ String severityPrefix = "Severity: ";
+ return this.checkPrefixAndRun(str, severityPrefix,
+ (line) ->
+ {
+ String sourceString = trySubstring(str, severityPrefix.length());
+ this.severity = EGLMessageSeverity.get(sourceString);
+ this.parserStage++;
+ });
+ case 5:
+ String messagePrefix = "Message: ";
+ return this.checkPrefixAndRun(str, messagePrefix,
+ (line) ->
+ {
+ this.message = trySubstring(str, messagePrefix.length());
+ this.parserStage++;
+ });
+ default:
+ return false;
+ }
+ }
+
+
+
+ //================//
+ // helper methods //
+ //================//
+
+ /**
+ * Returns true and increments the parserStage
+ * if the message and expected strings are the same.
+ */
+ private boolean checkExactAndIncStage(String message, String expectedString)
+ {
+ boolean equal = message.equals(expectedString);
+ if (equal)
+ {
+ this.parserStage++;
+ }
+ return equal;
+ }
+
+ /**
+ * Returns true and increments the parserStage
+ * if the message starts with the given prefix.
+ */
+ private boolean checkPrefixAndRun(String message, String expectedPrefix, Consumer successConsumer)
+ {
+ boolean equal = message.startsWith(expectedPrefix);
+ if (equal)
+ {
+ successConsumer.accept(message);
+ }
+ return equal;
+ }
+ /** returns "" if the string isn't long enough */
+ private static String trySubstring(String string, int beginIndex)
+ {
+ if (beginIndex > string.length())
+ {
+ // prevent index-out-of-bounds errors
+ // if the message isn't what we expected
+ return "";
+ }
+
+ return string.substring(beginIndex);
+ }
+
+
+}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessageOutputStream.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessageOutputStream.java
similarity index 78%
rename from core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessageOutputStream.java
rename to core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessageOutputStream.java
index 70463061f..b29e5df22 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessageOutputStream.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessages/GLMessageOutputStream.java
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-package com.seibel.distanthorizons.core.util.objects;
+package com.seibel.distanthorizons.core.util.objects.GLMessages;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -27,12 +27,12 @@ import java.util.function.Consumer;
public final class GLMessageOutputStream extends OutputStream
{
final Consumer func;
- final GLMessage.Builder builder;
+ final GLMessageBuilder builder;
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- public GLMessageOutputStream(Consumer func, GLMessage.Builder builder)
+ public GLMessageOutputStream(Consumer func, GLMessageBuilder builder)
{
this.func = func;
this.builder = builder;
@@ -41,24 +41,30 @@ public final class GLMessageOutputStream extends OutputStream
@Override
public void write(int b)
{
- buffer.write(b);
- if (b == '\n') flush();
+ this.buffer.write(b);
+ if (b == '\n')
+ {
+ this.flush();
+ }
}
@Override
public void flush()
{
- String str = buffer.toString();
- GLMessage msg = builder.add(str);
- if (msg != null) func.accept(msg);
- buffer.reset();
+ String str = this.buffer.toString();
+ GLMessage msg = this.builder.add(str);
+ if (msg != null)
+ {
+ this.func.accept(msg);
+ }
+ this.buffer.reset();
}
@Override
public void close() throws IOException
{
- flush();
- buffer.close();
+ this.flush();
+ this.buffer.close();
}
}
diff --git a/core/src/test/java/tests/GLMessageTest.java b/core/src/test/java/tests/GLMessageTest.java
index 798e8534c..a96c8b354 100644
--- a/core/src/test/java/tests/GLMessageTest.java
+++ b/core/src/test/java/tests/GLMessageTest.java
@@ -19,7 +19,7 @@
package tests;
-import com.seibel.distanthorizons.core.util.objects.GLMessage;
+import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
import org.junit.Assert;
import org.junit.Test;
@@ -28,66 +28,88 @@ import java.util.ArrayList;
public class GLMessageTest
{
public static final String MESSAGE_ID = "0x20071";
- public static final GLMessage.ESource MESSAGE_SOURCE = GLMessage.ESource.API;
- public static final GLMessage.EType MESSAGE_TYPE = GLMessage.EType.OTHER;
- public static final GLMessage.ESeverity MESSAGE_SEVERITY = GLMessage.ESeverity.NOTIFICATION;
+ public static final EGLMessageSource MESSAGE_SOURCE = EGLMessageSource.API;
+ public static final EGLMessageType MESSAGE_TYPE = EGLMessageType.OTHER;
+ public static final EGLMessageSeverity MESSAGE_SEVERITY = EGLMessageSeverity.NOTIFICATION;
public static final String MESSAGE = "Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations.";
/** This is how debug messages were sent prior to Minecraft 1.20.2 */
- private static final String[] PRE_1_20_2_MESSAGE_ARRAY =
+ private static final String[] OLD_MESSAGE_ARRAY =
{
"[LWJGL] OpenGL debug message"
- ,"ID", ":", "0x20071"
- ,"Source", ":", "API"
- ,"Type", ":", "OTHER"
- ,"Severity", ":", "NOTIFICATION"
- ,"Message", ":", "Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations."
+ ,"ID", ":", MESSAGE_ID
+ ,"Source", ":", MESSAGE_SOURCE.name
+ ,"Type", ":", MESSAGE_TYPE.name
+ ,"Severity", ":", MESSAGE_SEVERITY.name
+ ,"Message", ":", MESSAGE
// optional addition to force the builder into noticing the message ended, shouldn't be necessary
//,"[LWJGL] OpenGL debug message"
};
/** This is how debug messages were sent after (and including) Minecraft 1.20.2 */
- private static final String[] POST_1_20_2_MESSAGE_ARRAY =
+ private static final String[] NEW_MESSAGE_ARRAY =
{
"[LWJGL] OpenGL debug message"
- ,"ID: 0x20071"
- ,"Source: API"
- ,"Type: OTHER"
- ,"Severity: NOTIFICATION"
- ,"Message: Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations."
-
+ ,"ID: " + MESSAGE_ID
+ ,"Source: " + MESSAGE_SOURCE.name
+ ,"Type: " + MESSAGE_TYPE.name
+ ,"Severity: " + MESSAGE_SEVERITY.name
+ ,"Message: " + MESSAGE
+
// optional addition to force the builder into noticing the message ended, shouldn't be necessary
//,"[LWJGL] OpenGL debug message"
};
+ public final GLMessageBuilder messageBuilder = new GLMessageBuilder(null, null, null);
+
+ //=======//
+ // tests //
+ //=======//
+
@Test
public void preMc1_20_2()
{
ArrayList messageList = new ArrayList<>();
- for (String str : PRE_1_20_2_MESSAGE_ARRAY)
+ for (String str : OLD_MESSAGE_ARRAY)
{
- GLMessage message = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER.add(str);
+ GLMessage message = this.messageBuilder.add(str);
if (message != null)
{
messageList.add(message);
}
}
- //Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
- //testMessage(messageList.get(0));
+ Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
+ messageMatchesExpected(messageList.get(0));
}
@Test
public void mc1_20_2()
{
- // TODO
+ ArrayList messageList = new ArrayList<>();
+ for (String str : NEW_MESSAGE_ARRAY)
+ {
+ GLMessage message = this.messageBuilder.add(str);
+ if (message != null)
+ {
+ messageList.add(message);
+ }
+ }
+
+ Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
+ messageMatchesExpected(messageList.get(0));
}
+
+ //================//
+ // helper methods //
+ //================//
+
private static void messageMatchesExpected(GLMessage testMessage)
{
Assert.assertEquals(MESSAGE_ID, testMessage.id);
@@ -97,4 +119,6 @@ public class GLMessageTest
Assert.assertEquals(MESSAGE, testMessage.message);
}
+
+
}